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 => { 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, }); };