Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 0 additions & 2 deletions .github/workflows/web-ext-lint.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,6 @@ name: web-ext lint
on:
pull_request:
push:
Comment thread
blacklizardcode marked this conversation as resolved.
branches:
- main
paths-ignore:
- .gitignore
- LICENCE
Expand Down
4 changes: 2 additions & 2 deletions manifest.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"manifest_version": 2,
"name": "Magister-Autologin",
"version": "1.1.0",
"version": "1.2.0",

"description": "Automatically logs into magister for you",
"browser_action": {
Expand All @@ -11,7 +11,7 @@
"content_scripts": [
{
"matches": ["*://*.magister.net/account/*"],
"js": ["script/autologin.js"],
"js": ["script/sharedencryption.js", "script/autologin.js"],
"run_at": "document_idle"
Comment thread
blacklizardcode marked this conversation as resolved.
}
],
Expand Down
1 change: 1 addition & 0 deletions popup/popup.html
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ <h1>Magister Autologin</h1>
<input id="username" type="text" placeholder="Username">
<input id="password" type="password" placeholder="Password">
<button id="saveBtn">Save Setting</button>
<script src="../script/sharedencryption.js"></script>
<script src="popup.js"></script>
</body>
</html>
26 changes: 20 additions & 6 deletions popup/popup.js
Original file line number Diff line number Diff line change
@@ -1,18 +1,26 @@
const keyPromise = getOrCreateCryptoKey();

document.getElementById("saveBtn").addEventListener("click", async () => {
const key = await keyPromise;

const enabled = document.getElementById("enabled").checked;
const username = document.getElementById("username").value;
const password = document.getElementById("password").value;


const usernameEnc = await encryptString(key, username);
const passwordEnc = await encryptString(key, password);

await browser.storage.local.set({
"magister-autologin-enabled": enabled,
"magister-autologin-username": username,
"magister-autologin-password": password
"magister-autologin-username": usernameEnc,
"magister-autologin-password": passwordEnc
});
});


document.addEventListener("DOMContentLoaded", async () => {
const key = await keyPromise;
const enabledInput = document.getElementById("enabled");
const usernameInput = document.getElementById("username");
const passwordInput = document.getElementById("password");
Expand All @@ -27,11 +35,17 @@ document.addEventListener("DOMContentLoaded", async () => {
enabledInput.checked = stored["magister-autologin-enabled"];
}

if (typeof stored["magister-autologin-username"] === "string") {
usernameInput.value = stored["magister-autologin-username"];
const storedUsername = stored["magister-autologin-username"];
if (storedUsername && typeof storedUsername === "object" && storedUsername.iv && storedUsername.data) {
usernameInput.value = await decryptString(key, storedUsername);
} else if (typeof storedUsername === "string") {
usernameInput.value = storedUsername; // fallback for old plain-text values
}

if (typeof stored["magister-autologin-password"] === "string") {
passwordInput.value = stored["magister-autologin-password"];
const storedPassword = stored["magister-autologin-password"];
if (storedPassword && typeof storedPassword === "object" && storedPassword.iv && storedPassword.data) {
passwordInput.value = await decryptString(key, storedPassword);
} else if (typeof storedPassword === "string") {
passwordInput.value = storedPassword; // fallback for old plain-text values
Comment thread
blacklizardcode marked this conversation as resolved.
}
});
22 changes: 20 additions & 2 deletions script/autologin.js
Original file line number Diff line number Diff line change
@@ -1,14 +1,32 @@
async function getCredentials() {
const key = await getOrCreateCryptoKey();
const data = await browser.storage.local.get([
"magister-autologin-enabled",
"magister-autologin-username",
"magister-autologin-password"
]);

const storedUsername = data["magister-autologin-username"];
const storedPassword = data["magister-autologin-password"];

let username = "";
if (storedUsername && typeof storedUsername === "object" && storedUsername.iv && storedUsername.data) {
username = await decryptString(key, storedUsername);
} else if (typeof storedUsername === "string") {
username = storedUsername;
}

let password = "";
if (storedPassword && typeof storedPassword === "object" && storedPassword.iv && storedPassword.data) {
password = await decryptString(key, storedPassword);
} else if (typeof storedPassword === "string") {
password = storedPassword;
}

Comment thread
blacklizardcode marked this conversation as resolved.
return {
enabled: data["magister-autologin-enabled"] || "",
Comment thread
blacklizardcode marked this conversation as resolved.
username: data["magister-autologin-username"] || "",
password: data["magister-autologin-password"] || ""
username,
password
};
}

Expand Down
67 changes: 67 additions & 0 deletions script/sharedencryption.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
function arrayBufferToBase64(buffer) {
let binary = '';
let bytes = new Uint8Array(buffer);
for (let b of bytes) binary += String.fromCharCode(b);
return btoa(binary);
}
function base64ToArrayBuffer(base64) {
let binary = atob(base64);
let bytes = new Uint8Array(binary.length);
for (let i = 0; i < binary.length; i++) bytes[i] = binary.charCodeAt(i);
return bytes.buffer;
}

async function getOrCreateCryptoKey() {
// Check if the key exists in storage
let data = await browser.storage.local.get("encryptionKey");
let key;
if (!data.encryptionKey) {
// Generate a random AES key
key = await crypto.subtle.generateKey(
{ name: "AES-GCM", length: 256 },
true,
["encrypt", "decrypt"]
);
// Export key to base64
const raw = await crypto.subtle.exportKey("raw", key);
const b64 = arrayBufferToBase64(raw);
await browser.storage.local.set({ encryptionKey: b64 });
} else {
// Import the stored key
const raw = base64ToArrayBuffer(data.encryptionKey);
Comment thread
blacklizardcode marked this conversation as resolved.
key = await crypto.subtle.importKey(
"raw",
raw,
{ name: "AES-GCM" },
false,
["encrypt", "decrypt"]
);
}
return key;
}

async function encryptString(key, plaintext) {
const enc = new TextEncoder();
const iv = crypto.getRandomValues(new Uint8Array(12));
const ciphertext = await crypto.subtle.encrypt(
{ name: "AES-GCM", iv },
key,
enc.encode(plaintext)
);
return {
iv: arrayBufferToBase64(iv.buffer),
data: arrayBufferToBase64(ciphertext),
};
}

async function decryptString(key, encryptedObj) {
const iv = base64ToArrayBuffer(encryptedObj.iv);
const data = base64ToArrayBuffer(encryptedObj.data);
const dec = new TextDecoder();
const plaintext = await crypto.subtle.decrypt(
{ name: "AES-GCM", iv: new Uint8Array(iv) },
key,
data
);
return dec.decode(plaintext);
Comment thread
blacklizardcode marked this conversation as resolved.
}
Loading