poc
This commit is contained in:
parent
d85ebaf95d
commit
ece1fb6ff5
|
@ -1,6 +1,6 @@
|
|||
{
|
||||
"name": "sessions-ext",
|
||||
"version": "0.0.1",
|
||||
"version": "0.1.0",
|
||||
"description": "",
|
||||
"scripts": {
|
||||
"build": "parcel build src/manifest.json --no-content-hash --no-source-maps --dist-dir dist --detailed-report 0",
|
||||
|
|
|
@ -1,15 +1,20 @@
|
|||
import { LoginMessage, Message, MessageType } from './message';
|
||||
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(
|
||||
(message: Message, sender, sendResponse) => {
|
||||
switch (message.type) {
|
||||
case MessageType.LOGIN:
|
||||
handleLogin(message);
|
||||
async (message: Message, sender, sendResponse) => {
|
||||
try {
|
||||
switch (message.type) {
|
||||
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,
|
||||
});
|
||||
|
||||
console.log(sid);
|
||||
|
||||
if (sid) {
|
||||
const success = await tryOpenOverview(message.url);
|
||||
if (success) {
|
||||
|
@ -93,7 +96,7 @@ const createOrUpdateCookie = async (server: string, sid: string) => {
|
|||
method: 'PUT',
|
||||
body: sid,
|
||||
headers: {
|
||||
'X-Api-Key': opts.apiKey,
|
||||
[API_KEY_HEADER]: opts.apiKey,
|
||||
'Content-Type': 'text/plain',
|
||||
},
|
||||
});
|
||||
|
@ -108,7 +111,7 @@ const getSid = async (server: string): Promise<string> => {
|
|||
const resp = await fetch(url, {
|
||||
method: 'GET',
|
||||
headers: {
|
||||
'X-Api-Key': opts.apiKey,
|
||||
[API_KEY_HEADER]: opts.apiKey,
|
||||
},
|
||||
});
|
||||
|
||||
|
|
|
@ -1,4 +1,6 @@
|
|||
import { LoginMessage, MessageType } from './message';
|
||||
import { LoginMessage, LoginResponse, MessageType } from './message';
|
||||
|
||||
let isLoggingIn = false;
|
||||
|
||||
const renderUI = () => {
|
||||
document
|
||||
|
@ -21,21 +23,35 @@ const renderUI = () => {
|
|||
});
|
||||
};
|
||||
|
||||
const handleClick = (e: MouseEvent) => {
|
||||
const handleClick = async (e: MouseEvent) => {
|
||||
if (!(e.currentTarget instanceof HTMLAnchorElement)) {
|
||||
return;
|
||||
}
|
||||
|
||||
e.preventDefault();
|
||||
|
||||
if (isLoggingIn) {
|
||||
return;
|
||||
}
|
||||
|
||||
isLoggingIn = true;
|
||||
|
||||
const url = new URL(e.currentTarget.href);
|
||||
const server = extractServerFromURL(url);
|
||||
chrome.runtime.sendMessage({
|
||||
type: MessageType.LOGIN,
|
||||
server,
|
||||
loginUrl: url.toString(),
|
||||
url: url.protocol + '//' + url.host.replace('www', server),
|
||||
} as LoginMessage);
|
||||
chrome.runtime
|
||||
.sendMessage({
|
||||
type: MessageType.LOGIN,
|
||||
server,
|
||||
loginUrl: url.toString(),
|
||||
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 => {
|
||||
|
|
|
@ -1,11 +1,13 @@
|
|||
const ITERATIONS = 100000;
|
||||
const SALT_LENGTH = 16;
|
||||
const IV_LENGTH = 12;
|
||||
|
||||
const enc = new TextEncoder();
|
||||
const dec = new TextDecoder();
|
||||
|
||||
export const encrypt = async (data: string, password: string) => {
|
||||
const salt = crypto.getRandomValues(new Uint8Array(16));
|
||||
const iv = crypto.getRandomValues(new Uint8Array(12));
|
||||
const salt = crypto.getRandomValues(new Uint8Array(SALT_LENGTH));
|
||||
const iv = crypto.getRandomValues(new Uint8Array(IV_LENGTH));
|
||||
const passwordKey = await getPasswordKey(password);
|
||||
const aesKey = await deriveKey(passwordKey, salt, ['encrypt']);
|
||||
const encryptedContent = await crypto.subtle.encrypt(
|
||||
|
@ -18,7 +20,7 @@ export const encrypt = async (data: string, password: string) => {
|
|||
);
|
||||
|
||||
const encryptedContentArr = new Uint8Array(encryptedContent);
|
||||
let buf = new Uint8Array(
|
||||
const buf = new Uint8Array(
|
||||
salt.byteLength + iv.byteLength + encryptedContentArr.byteLength
|
||||
);
|
||||
buf.set(salt, 0);
|
||||
|
@ -29,9 +31,9 @@ export const encrypt = async (data: string, password: string) => {
|
|||
|
||||
export const decrypt = async (encryptedData: string, password: string) => {
|
||||
const encryptedDataBuff = base64ToBuf(encryptedData);
|
||||
const salt = encryptedDataBuff.slice(0, 16);
|
||||
const iv = encryptedDataBuff.slice(16, 16 + 12);
|
||||
const data = encryptedDataBuff.slice(16 + 12);
|
||||
const salt = encryptedDataBuff.slice(0, SALT_LENGTH);
|
||||
const iv = encryptedDataBuff.slice(SALT_LENGTH, SALT_LENGTH + IV_LENGTH);
|
||||
const data = encryptedDataBuff.slice(SALT_LENGTH + IV_LENGTH);
|
||||
const passwordKey = await getPasswordKey(password);
|
||||
const aesKey = await deriveKey(passwordKey, salt, ['decrypt']);
|
||||
const decryptedContent = await crypto.subtle.decrypt(
|
||||
|
|
BIN
src/icon.png
BIN
src/icon.png
Binary file not shown.
Before Width: | Height: | Size: 1.1 KiB After Width: | Height: | Size: 5.8 KiB |
|
@ -1,7 +1,7 @@
|
|||
{
|
||||
"name": "Awesome Extension",
|
||||
"version": "0.0.0",
|
||||
"description": "An awesome new browser extension",
|
||||
"name": "Sessions",
|
||||
"version": "0.1.0",
|
||||
"description": "A browser extension aiming to simplify coplaying",
|
||||
"homepage_url": "https://tribalwarshelp.com/",
|
||||
"manifest_version": 3,
|
||||
"minimum_chrome_version": "100",
|
||||
|
@ -13,10 +13,10 @@
|
|||
"default_popup": "popup.html"
|
||||
},
|
||||
"permissions": ["storage", "cookies", "activeTab", "tabs"],
|
||||
"host_permissions": ["https://*.tribalwars.net/*"],
|
||||
"host_permissions": ["https://*.tribalwars.net/*", "https://*.plemiona.pl/*"],
|
||||
"content_scripts": [
|
||||
{
|
||||
"matches": ["https://www.tribalwars.net/*"],
|
||||
"matches": ["https://www.tribalwars.net/*", "https://www.plemiona.pl/*"],
|
||||
"js": ["content.ts"],
|
||||
"run_at": "document_end"
|
||||
}
|
||||
|
@ -24,5 +24,6 @@
|
|||
"background": {
|
||||
"service_worker": "background.ts",
|
||||
"type": "module"
|
||||
}
|
||||
},
|
||||
"author": "Dawid Wysokiński"
|
||||
}
|
||||
|
|
|
@ -10,3 +10,7 @@ export type LoginMessage = {
|
|||
};
|
||||
|
||||
export type Message = LoginMessage;
|
||||
|
||||
export type LoginResponse = {
|
||||
error?: string;
|
||||
};
|
||||
|
|
|
@ -11,7 +11,7 @@
|
|||
</head>
|
||||
<body>
|
||||
<main>
|
||||
<h1>Hello</h1>
|
||||
<h1>Options</h1>
|
||||
<section id="options">
|
||||
<form>
|
||||
<label
|
||||
|
|
Loading…
Reference in New Issue