This commit is contained in:
Dawid Wysokiński 2022-11-27 08:26:10 +01:00
parent d85ebaf95d
commit ece1fb6ff5
Signed by: Kichiyaki
GPG Key ID: B5445E357FB8B892
8 changed files with 57 additions and 31 deletions

View File

@ -1,6 +1,6 @@
{ {
"name": "sessions-ext", "name": "sessions-ext",
"version": "0.0.1", "version": "0.1.0",
"description": "", "description": "",
"scripts": { "scripts": {
"build": "parcel build src/manifest.json --no-content-hash --no-source-maps --dist-dir dist --detailed-report 0", "build": "parcel build src/manifest.json --no-content-hash --no-source-maps --dist-dir dist --detailed-report 0",

View File

@ -1,15 +1,20 @@
import { LoginMessage, Message, MessageType } from './message'; import { LoginMessage, LoginResponse, Message, MessageType } from './message';
import { optionsStorage } from './options-storage'; import { optionsStorage } from './options-storage';
import { decrypt, encrypt } from './crypto'; import { decrypt, encrypt } from './crypto';
const COOKIE_NAME = 'sid'; const COOKIE_NAME = 'sid';
const HTTP_STATUS_OK = 200; const HTTP_STATUS_OK = 200;
const API_KEY_HEADER = 'X-Api-Key';
chrome.runtime.onMessage.addListener( chrome.runtime.onMessage.addListener(
(message: Message, sender, sendResponse) => { async (message: Message, sender, sendResponse) => {
switch (message.type) { try {
case MessageType.LOGIN: switch (message.type) {
handleLogin(message); case MessageType.LOGIN:
await handleLogin(message);
}
} catch (err: any) {
sendResponse({ error: err.message } as LoginResponse);
} }
} }
); );
@ -20,8 +25,6 @@ const handleLogin = async (message: LoginMessage) => {
url: message.url, url: message.url,
}); });
console.log(sid);
if (sid) { if (sid) {
const success = await tryOpenOverview(message.url); const success = await tryOpenOverview(message.url);
if (success) { if (success) {
@ -93,7 +96,7 @@ const createOrUpdateCookie = async (server: string, sid: string) => {
method: 'PUT', method: 'PUT',
body: sid, body: sid,
headers: { headers: {
'X-Api-Key': opts.apiKey, [API_KEY_HEADER]: opts.apiKey,
'Content-Type': 'text/plain', 'Content-Type': 'text/plain',
}, },
}); });
@ -108,7 +111,7 @@ const getSid = async (server: string): Promise<string> => {
const resp = await fetch(url, { const resp = await fetch(url, {
method: 'GET', method: 'GET',
headers: { headers: {
'X-Api-Key': opts.apiKey, [API_KEY_HEADER]: opts.apiKey,
}, },
}); });

View File

@ -1,4 +1,6 @@
import { LoginMessage, MessageType } from './message'; import { LoginMessage, LoginResponse, MessageType } from './message';
let isLoggingIn = false;
const renderUI = () => { const renderUI = () => {
document document
@ -21,21 +23,35 @@ const renderUI = () => {
}); });
}; };
const handleClick = (e: MouseEvent) => { const handleClick = async (e: MouseEvent) => {
if (!(e.currentTarget instanceof HTMLAnchorElement)) { if (!(e.currentTarget instanceof HTMLAnchorElement)) {
return; return;
} }
e.preventDefault(); e.preventDefault();
if (isLoggingIn) {
return;
}
isLoggingIn = true;
const url = new URL(e.currentTarget.href); const url = new URL(e.currentTarget.href);
const server = extractServerFromURL(url); const server = extractServerFromURL(url);
chrome.runtime.sendMessage({ chrome.runtime
type: MessageType.LOGIN, .sendMessage({
server, type: MessageType.LOGIN,
loginUrl: url.toString(), server,
url: url.protocol + '//' + url.host.replace('www', server), loginUrl: url.toString(),
} as LoginMessage); url: url.protocol + '//' + url.host.replace('www', server),
} as LoginMessage)
.then((resp: LoginResponse) => {
isLoggingIn = false;
if (!resp?.error) {
return;
}
console.error(resp.error);
});
}; };
const extractServerFromURL = (url: URL): string => { const extractServerFromURL = (url: URL): string => {

View File

@ -1,11 +1,13 @@
const ITERATIONS = 100000; const ITERATIONS = 100000;
const SALT_LENGTH = 16;
const IV_LENGTH = 12;
const enc = new TextEncoder(); const enc = new TextEncoder();
const dec = new TextDecoder(); const dec = new TextDecoder();
export const encrypt = async (data: string, password: string) => { export const encrypt = async (data: string, password: string) => {
const salt = crypto.getRandomValues(new Uint8Array(16)); const salt = crypto.getRandomValues(new Uint8Array(SALT_LENGTH));
const iv = crypto.getRandomValues(new Uint8Array(12)); const iv = crypto.getRandomValues(new Uint8Array(IV_LENGTH));
const passwordKey = await getPasswordKey(password); const passwordKey = await getPasswordKey(password);
const aesKey = await deriveKey(passwordKey, salt, ['encrypt']); const aesKey = await deriveKey(passwordKey, salt, ['encrypt']);
const encryptedContent = await crypto.subtle.encrypt( const encryptedContent = await crypto.subtle.encrypt(
@ -18,7 +20,7 @@ export const encrypt = async (data: string, password: string) => {
); );
const encryptedContentArr = new Uint8Array(encryptedContent); const encryptedContentArr = new Uint8Array(encryptedContent);
let buf = new Uint8Array( const buf = new Uint8Array(
salt.byteLength + iv.byteLength + encryptedContentArr.byteLength salt.byteLength + iv.byteLength + encryptedContentArr.byteLength
); );
buf.set(salt, 0); buf.set(salt, 0);
@ -29,9 +31,9 @@ export const encrypt = async (data: string, password: string) => {
export const decrypt = async (encryptedData: string, password: string) => { export const decrypt = async (encryptedData: string, password: string) => {
const encryptedDataBuff = base64ToBuf(encryptedData); const encryptedDataBuff = base64ToBuf(encryptedData);
const salt = encryptedDataBuff.slice(0, 16); const salt = encryptedDataBuff.slice(0, SALT_LENGTH);
const iv = encryptedDataBuff.slice(16, 16 + 12); const iv = encryptedDataBuff.slice(SALT_LENGTH, SALT_LENGTH + IV_LENGTH);
const data = encryptedDataBuff.slice(16 + 12); const data = encryptedDataBuff.slice(SALT_LENGTH + IV_LENGTH);
const passwordKey = await getPasswordKey(password); const passwordKey = await getPasswordKey(password);
const aesKey = await deriveKey(passwordKey, salt, ['decrypt']); const aesKey = await deriveKey(passwordKey, salt, ['decrypt']);
const decryptedContent = await crypto.subtle.decrypt( const decryptedContent = await crypto.subtle.decrypt(

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.1 KiB

After

Width:  |  Height:  |  Size: 5.8 KiB

View File

@ -1,7 +1,7 @@
{ {
"name": "Awesome Extension", "name": "Sessions",
"version": "0.0.0", "version": "0.1.0",
"description": "An awesome new browser extension", "description": "A browser extension aiming to simplify coplaying",
"homepage_url": "https://tribalwarshelp.com/", "homepage_url": "https://tribalwarshelp.com/",
"manifest_version": 3, "manifest_version": 3,
"minimum_chrome_version": "100", "minimum_chrome_version": "100",
@ -13,10 +13,10 @@
"default_popup": "popup.html" "default_popup": "popup.html"
}, },
"permissions": ["storage", "cookies", "activeTab", "tabs"], "permissions": ["storage", "cookies", "activeTab", "tabs"],
"host_permissions": ["https://*.tribalwars.net/*"], "host_permissions": ["https://*.tribalwars.net/*", "https://*.plemiona.pl/*"],
"content_scripts": [ "content_scripts": [
{ {
"matches": ["https://www.tribalwars.net/*"], "matches": ["https://www.tribalwars.net/*", "https://www.plemiona.pl/*"],
"js": ["content.ts"], "js": ["content.ts"],
"run_at": "document_end" "run_at": "document_end"
} }
@ -24,5 +24,6 @@
"background": { "background": {
"service_worker": "background.ts", "service_worker": "background.ts",
"type": "module" "type": "module"
} },
"author": "Dawid Wysokiński"
} }

View File

@ -10,3 +10,7 @@ export type LoginMessage = {
}; };
export type Message = LoginMessage; export type Message = LoginMessage;
export type LoginResponse = {
error?: string;
};

View File

@ -11,7 +11,7 @@
</head> </head>
<body> <body>
<main> <main>
<h1>Hello</h1> <h1>Options</h1>
<section id="options"> <section id="options">
<form> <form>
<label <label