sessions-ext/src/background.ts

143 lines
3.3 KiB
TypeScript

import { LoginMessage, ErrorResponse, 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 ErrorResponse);
}
}
);
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) {
try {
await setSid(message.url, sidFromApi);
} catch (e) {}
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,
});
};