This commit is contained in:
Dawid Wysokiński 2022-11-26 08:58:43 +01:00
parent 00ddc08afd
commit d85ebaf95d
Signed by: Kichiyaki
GPG Key ID: B5445E357FB8B892
9 changed files with 121 additions and 24 deletions

2
.gitignore vendored
View File

@ -1,4 +1,4 @@
distribution
dist
.idea
node_modules
.parcel-cache

View File

@ -3,8 +3,8 @@
"version": "0.0.1",
"description": "",
"scripts": {
"build": "parcel build src/manifest.json --no-content-hash --no-source-maps --dist-dir distribution --detailed-report 0",
"watch": "parcel watch src/manifest.json --dist-dir distribution --no-cache --no-hmr",
"build": "parcel build src/manifest.json --no-content-hash --no-source-maps --dist-dir dist --detailed-report 0",
"watch": "parcel watch src/manifest.json --dist-dir dist --no-cache --no-hmr",
"run:chromium": "web-ext run -t chromium"
},
"author": {
@ -24,7 +24,7 @@
"since 2017-06"
],
"webExt": {
"sourceDir": "distribution",
"sourceDir": "dist",
"run": {
"startUrl": [
"https://www.tribalwars.net"

View File

@ -3,6 +3,7 @@ import { optionsStorage } from './options-storage';
import { decrypt, encrypt } from './crypto';
const COOKIE_NAME = 'sid';
const HTTP_STATUS_OK = 200;
chrome.runtime.onMessage.addListener(
(message: Message, sender, sendResponse) => {
@ -14,27 +15,123 @@ chrome.runtime.onMessage.addListener(
);
const handleLogin = async (message: LoginMessage) => {
const cookie = await chrome.cookies.get({
const sid = await chrome.cookies.get({
name: COOKIE_NAME,
url: message.url,
});
console.log(cookie);
console.log(sid);
if (cookie) {
const opts = await optionsStorage.getAll();
const test1 = await encrypt(cookie.value, opts.encryptionPassword);
const test2 = await decrypt(test1, opts.encryptionPassword);
console.log(opts.encryptionPassword, test1, test2);
if (sid) {
const success = await tryOpenOverview(message.url);
if (success) {
await createOrUpdateCookie(message.server, await encryptCookie(sid));
await openOverview(message.url);
return;
}
}
const url = new URL(message.url);
url.pathname = '/game.php';
url.searchParams.set('screen', 'overview_villages');
const resp = await fetch(url.toString(), {
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',
redirect: 'manual',
});
console.log(resp.status, resp.redirected);
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: {
'X-Api-Key': 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: {
'X-Api-Key': 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,
});
};

View File

@ -33,6 +33,7 @@ const handleClick = (e: MouseEvent) => {
chrome.runtime.sendMessage({
type: MessageType.LOGIN,
server,
loginUrl: url.toString(),
url: url.protocol + '//' + url.host.replace('www', server),
} as LoginMessage);
};

View File

@ -1,5 +1,3 @@
// https://github.com/bradyjoslin/webcrypto-example/blob/master/script.js
const ITERATIONS = 100000;
const enc = new TextEncoder();

View File

@ -12,7 +12,7 @@
"default_title": "Sessions",
"default_popup": "popup.html"
},
"permissions": ["storage", "cookies"],
"permissions": ["storage", "cookies", "activeTab", "tabs"],
"host_permissions": ["https://*.tribalwars.net/*"],
"content_scripts": [
{

View File

@ -5,6 +5,7 @@ export enum MessageType {
export type LoginMessage = {
type: MessageType.LOGIN;
url: string;
loginUrl: string;
server: string;
};

View File

@ -2,8 +2,8 @@ import OptionsSync from 'webext-options-sync';
export const optionsStorage = new OptionsSync({
defaults: {
apiUrl: 'https://tribalwarshelp.com',
apiToken: '',
apiUrl: 'http://localhost:9234',
apiKey: '',
encryptionPassword: 'password',
},
migrations: [OptionsSync.migrations.removeUnused],

View File

@ -19,8 +19,8 @@
<input name="apiUrl" type="text" />
</label>
<label
>API Token
<input name="apiToken" type="text" />
>API Key
<input name="apiKey" type="text" />
</label>
<label
>Encryption password