2025-05-03 18:16:36 -04:00
{% extends "layout.html" %}
{% block title %}Kawari Launcher{% endblock %}
{% block body %}
2025-05-03 20:33:41 -04:00
< main class = "p-3" >
< h1 > Kawari< / h1 >
2025-05-03 18:16:36 -04:00
2025-05-03 20:33:41 -04:00
< div class = "alert alert-primary" role = "alert" id = "alert" style = "display: none" >
< p id = "statusMessage" > < / p >
< / div >
< form id = "login" style = "max-width: 300px;" class = "mt-3 mb-3" >
2025-05-03 18:16:36 -04:00
< label for = "sqexid" class = "form-label" > Username< / label > < br >
< input type = 'text' id = 'sqexid' name = 'sqexid' class = "form-control" / > < br >
< label for = "password" class = "form-label" > Password< / label > < br >
< input id = 'password' name = 'password' class = "form-control" type = "password" / > < br >
< input type = "hidden" id = "_STORED_" name = "_STORED_" value = "34657" / >
< button type = 'submit' class = "btn btn-primary" > Login< / button >
< / form >
2025-05-03 20:33:41 -04:00
< input type = "button" class = "btn btn-primary btn-lg mt-3 mb-3" id = "play" value = "Play" onclick = "window.external.user('startPlay');" style = "display: none" / >
2025-05-03 20:44:59 -04:00
< div class = "btn-group mb-3" role = "group" >
2025-05-03 20:33:41 -04:00
< input type = "button" class = "btn btn-secondary" value = "System Info" onclick = "window.external.user('systemInfo');" / >
< input type = "button" class = "btn btn-secondary" value = "Config Tool" onclick = "window.external.user('configTransport');" / >
< / div >
2025-05-03 20:44:59 -04:00
< div class = "btn-group mb-3" role = "group" >
2025-05-03 20:33:41 -04:00
< input type = "button" class = "btn btn-outline-secondary" value = "Accept EULA" onclick = "window.external.user('eulaOk');" / >
< input type = "button" class = "btn btn-outline-secondary" value = "Accept Ex EULAs" onclick = "window.external.user('eulaExOk');" / >
< / div >
2025-05-03 20:44:59 -04:00
< p > < small > This is not an official login page. It will < i > not< / i > accept your official account's credentials, please do not enter them here!< / small > < / p >
2025-05-03 20:33:41 -04:00
< / main >
2025-05-03 18:16:36 -04:00
< script type = "text/javascript" >
let req;
function readystatechange(event) {
if (req.readyState == 4) {
// This login endpoint sends a "window.external.user" which we need to evaludate.
eval(req.response);
}
}
function error(event) {
2025-05-03 20:33:41 -04:00
window.external.user('login=auth,ng,err,' + req.response);
2025-05-03 18:16:36 -04:00
}
function login() {
let sqexid = document.getElementById('sqexid').value;
let password = document.getElementById('password').value;
2025-05-03 20:33:41 -04:00
let otppw = "";
2025-05-03 18:16:36 -04:00
let stored = document.getElementById('_STORED_').value;
req = new XMLHttpRequest();
req.addEventListener("readystatechange", readystatechange);
req.addEventListener("error", error);
req.open("POST", "http://ffxiv-login.square.localhost/oauth/ffxivarr/login/login.send");
req.setRequestHeader("Content-Type", "application/x-www-form-urlencoded");
req.send("sqexid=" + sqexid + "& password=" + password + "& otppw=" + otppw + "& _STORED_=" + stored);
}
2025-05-03 20:33:41 -04:00
function sendAlert(text) {
document.getElementById('statusMessage').innerText = text;
document.getElementById('alert').style.display = "block";
}
2025-05-03 18:16:36 -04:00
function checkHandlerType(e) {
if ('function' != typeof e) throw new Error('Protocol Callback is not function.');
return e
}
function fromAppConfig(thing) {
2025-05-03 20:33:41 -04:00
//document.getElementById('replace-me').innerText += "config: " + JSON.stringify(thing);
2025-05-03 18:16:36 -04:00
}
window.fromAppConfig = this.checkHandlerType(fromAppConfig);
function fromAppWarn(thing) {
2025-05-03 20:33:41 -04:00
document.getElementById('statusMessage').innerText += "warn: " + JSON.stringify(thing);
2025-05-03 18:16:36 -04:00
}
window.fromAppWarn = this.checkHandlerType(fromAppWarn);
function fromAppStartVersionCheck(thing) {
2025-05-03 20:33:41 -04:00
sendAlert(thing.versionChecking);
2025-05-03 18:16:36 -04:00
// the official launcher does some preparation stuff here, and when it's finished it tells it the ID it just recieved
window.external.user('received=' + thing.ID);
}
window.fromAppStartVersionCheck = this.checkHandlerType(fromAppStartVersionCheck);
function fromAppDP(thing) {
2025-05-03 20:33:41 -04:00
//document.getElementById('replace-me').innerText += "dp: " + JSON.stringify(thing);
2025-05-03 18:16:36 -04:00
}
window.fromAppDP = this.checkHandlerType(fromAppDP);
function fromAppDisplaySettings(thing) {
2025-05-03 20:33:41 -04:00
//document.getElementById('replace-me').innerText += "display settings: " + JSON.stringify(thing);
2025-05-03 18:16:36 -04:00
}
window.fromAppDisplaySettings = this.checkHandlerType(fromAppDisplaySettings);
function fromAppResumeInfo(thing) {
2025-05-03 20:33:41 -04:00
// 3 means "ready to play"
if (thing.state == 3) {
document.getElementById("login").style.display = "none";
document.getElementById("play").style.display = "block";
}
2025-05-03 18:16:36 -04:00
// acknowledge
window.external.user('received=' + thing.ID);
}
window.fromAppResumeInfo = this.checkHandlerType(fromAppResumeInfo);
function fromAppLoginUrl(thing) {
2025-05-03 20:33:41 -04:00
//document.getElementById('replace-me').innerText += "login info: " + JSON.stringify(thing);
2025-05-03 18:16:36 -04:00
}
window.fromAppLoginUrl = this.checkHandlerType(fromAppLoginUrl);
function fromAppExAgree(thing) {
2025-05-03 20:33:41 -04:00
sendAlert("You need to accept the following Ex EULAs: " + thing.notAgreedExEulas);
2025-05-03 18:16:36 -04:00
}
window.fromAppExAgree = this.checkHandlerType(fromAppExAgree);
function fromAppStartDownload(thing) {
2025-05-03 20:33:41 -04:00
//document.getElementById('replace-me').innerText += "start download: " + JSON.stringify(thing);
2025-05-03 18:16:36 -04:00
}
window.fromAppStartDownload = this.checkHandlerType(fromAppStartDownload);
function fromAppDownloadProgress(thing) {
2025-05-03 20:33:41 -04:00
//document.getElementById('replace-me').innerText += "download prog: " + JSON.stringify(thing);
2025-05-03 18:16:36 -04:00
}
window.fromAppDownloadProgress = this.checkHandlerType(fromAppDownloadProgress);
function fromAppInstallProgress(thing) {
2025-05-03 20:33:41 -04:00
//document.getElementById('replace-me').innerText += "install prog: " + JSON.stringify(thing);
2025-05-03 18:16:36 -04:00
}
window.fromAppInstallProgress = this.checkHandlerType(fromAppInstallProgress);
function fromAppStartInstall(thing) {
2025-05-03 20:33:41 -04:00
//document.getElementById('replace-me').innerText += "start install: " + JSON.stringify(thing);
2025-05-03 18:16:36 -04:00
}
window.fromAppStartInstall = this.checkHandlerType(fromAppStartInstall);
function fromAppWaitPlay(thing) {
2025-05-03 20:33:41 -04:00
//document.getElementById('replace-me').innerText += "wait play: " + JSON.stringify(thing);
2025-05-03 18:16:36 -04:00
// the official launcher does some preparation stuff here, and when it's finished it tells it the ID it just recieved
window.external.user('received=' + thing.ID);
// it requests the config again?
window.external.user('requestConfig');
}
window.fromAppWaitPlay = this.checkHandlerType(fromAppWaitPlay);
function fromAppStartFileCheck(thing) {
2025-05-03 20:33:41 -04:00
//document.getElementById('replace-me').innerText += "file check: " + JSON.stringify(thing);
2025-05-03 18:16:36 -04:00
}
window.fromAppStartFileCheck = this.checkHandlerType(fromAppStartFileCheck);
function fromAppFileCheckProgress(thing) {
2025-05-03 20:33:41 -04:00
//document.getElementById('replace-me').innerText += "file check prog: " + JSON.stringify(thing);
2025-05-03 18:16:36 -04:00
}
window.fromAppFileCheckProgress = this.checkHandlerType(fromAppFileCheckProgress);
function fromAppFinishedFileCheck(thing) {
2025-05-03 20:33:41 -04:00
//document.getElementById('replace-me').innerText += "file check finished: " + JSON.stringify(thing);
2025-05-03 18:16:36 -04:00
}
window.fromAppFinishedFileCheck = this.checkHandlerType(fromAppFinishedFileCheck);
function fromAppServiceAgreement(thing) {
2025-05-03 20:33:41 -04:00
//document.getElementById('replace-me').innerText += "agreement: " + JSON.stringify(thing);
2025-05-03 18:16:36 -04:00
}
window.fromAppServiceAgreement = this.checkHandlerType(fromAppServiceAgreement);
function fromAppDialog(thing) {
2025-05-03 20:33:41 -04:00
//document.getElementById('replace-me').innerText += "dialog: " + JSON.stringify(thing);
2025-05-03 18:16:36 -04:00
}
window.fromAppDialog = this.checkHandlerType(fromAppDialog);
// this is what the retail launcher does
window.external.user('permissionFromApp=1');
window.external.user('requestDP');
window.external.user('requestConfig');
window.external.user('requestDisplaySettings');
window.external.user('requestResumeInfo');
// setup form submission
const form = document.getElementById("login");
form.addEventListener("submit", function (event) {
// ie11 is amazing
if (event.preventDefault) {
event.preventDefault();
} else {
event.returnValue = false;
}
login();
});
< / script >
{% endblock %}