141 lines
3.3 KiB
TypeScript
141 lines
3.3 KiB
TypeScript
import { LoginMessage, LoginResponse, Message, MessageType } from './message';
|
|
import { optionsStorage } from './options-storage';
|
|
import { decrypt, encrypt } from './crypto';
|
|
|
|
const COOKIE_NAME = 'sid';
|
|
const HTTP_STATUS_OK = 200;
|
|
const API_KEY_HEADER = 'X-Api-Key';
|
|
|
|
chrome.runtime.onMessage.addListener(
|
|
async (message: Message, sender, sendResponse) => {
|
|
try {
|
|
switch (message.type) {
|
|
case MessageType.LOGIN:
|
|
await handleLogin(message);
|
|
}
|
|
} catch (err: any) {
|
|
sendResponse({ error: err.message } as LoginResponse);
|
|
}
|
|
}
|
|
);
|
|
|
|
const handleLogin = async (message: LoginMessage) => {
|
|
const sid = await chrome.cookies.get({
|
|
name: COOKIE_NAME,
|
|
url: message.url,
|
|
});
|
|
|
|
if (sid) {
|
|
const success = await tryOpenOverview(message.url);
|
|
if (success) {
|
|
await createOrUpdateCookie(message.server, await encryptCookie(sid));
|
|
await openOverview(message.url);
|
|
return;
|
|
}
|
|
}
|
|
|
|
const sidFromApi = await getSid(message.server);
|
|
if (sidFromApi.length > 0) {
|
|
await setSid(message.url, sidFromApi);
|
|
if (await tryOpenOverview(message.url)) {
|
|
await openOverview(message.url);
|
|
return;
|
|
}
|
|
}
|
|
|
|
await fetch(message.loginUrl, {
|
|
method: 'GET',
|
|
credentials: 'include',
|
|
});
|
|
|
|
const newSid = await chrome.cookies.get({
|
|
name: COOKIE_NAME,
|
|
url: message.url,
|
|
});
|
|
if (!newSid) {
|
|
return;
|
|
}
|
|
|
|
await createOrUpdateCookie(message.server, await encryptCookie(newSid));
|
|
await openOverview(message.url);
|
|
};
|
|
|
|
const tryOpenOverview = async (base: string) => {
|
|
try {
|
|
const resp = await fetch(buildUrlToOverview(base), {
|
|
method: 'GET',
|
|
credentials: 'include',
|
|
redirect: 'error',
|
|
});
|
|
return resp.status == HTTP_STATUS_OK;
|
|
} catch (e) {
|
|
return false;
|
|
}
|
|
};
|
|
|
|
const openOverview = async (base: string) => {
|
|
await chrome.tabs.update({
|
|
url: buildUrlToOverview(base).toString(),
|
|
});
|
|
};
|
|
|
|
const buildUrlToOverview = (base: string) => {
|
|
const url = new URL(base);
|
|
url.pathname = '/game.php';
|
|
url.searchParams.set('screen', 'overview_villages');
|
|
return url;
|
|
};
|
|
|
|
const createOrUpdateCookie = async (server: string, sid: string) => {
|
|
const opts = await optionsStorage.getAll();
|
|
|
|
const url = new URL(opts.apiUrl);
|
|
url.pathname = `/api/v1/user/sessions/${server}`;
|
|
|
|
await fetch(url, {
|
|
method: 'PUT',
|
|
body: sid,
|
|
headers: {
|
|
[API_KEY_HEADER]: opts.apiKey,
|
|
'Content-Type': 'text/plain',
|
|
},
|
|
});
|
|
};
|
|
|
|
const getSid = async (server: string): Promise<string> => {
|
|
const opts = await optionsStorage.getAll();
|
|
|
|
const url = new URL(opts.apiUrl);
|
|
url.pathname = `/api/v1/user/sessions/${server}`;
|
|
|
|
const resp = await fetch(url, {
|
|
method: 'GET',
|
|
headers: {
|
|
[API_KEY_HEADER]: opts.apiKey,
|
|
},
|
|
});
|
|
|
|
const respBody = await resp.json();
|
|
if (!respBody.data?.sid) {
|
|
return '';
|
|
}
|
|
|
|
return respBody.data.sid;
|
|
};
|
|
|
|
const encryptCookie = async (cookie: chrome.cookies.Cookie) => {
|
|
const opts = await optionsStorage.getAll();
|
|
return await encrypt(cookie.value, opts.encryptionPassword);
|
|
};
|
|
|
|
const setSid = async (url: string, sid: string) => {
|
|
const opts = await optionsStorage.getAll();
|
|
await chrome.cookies.set({
|
|
url,
|
|
name: COOKIE_NAME,
|
|
value: await decrypt(sid, opts.encryptionPassword),
|
|
httpOnly: true,
|
|
secure: true,
|
|
});
|
|
};
|