-
Notifications
You must be signed in to change notification settings - Fork 29
Expand file tree
/
Copy pathscript.js
More file actions
69 lines (59 loc) · 2.59 KB
/
script.js
File metadata and controls
69 lines (59 loc) · 2.59 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
(function (global) {
'use strict';
const DECRYPTION_KEY = 'Th1s_1s_a_S@mpl3_S3cure_K3y_32ch';
async function sha256(message) {
const msgBuffer = new TextEncoder().encode(message);
const hashBuffer = await crypto.subtle.digest('SHA-256', msgBuffer);
const hashArray = Array.from(new Uint8Array(hashBuffer));
return hashArray.map(b => b.toString(16).padStart(2, '0')).join('');
}
function generateNonce(length = 8) {
const chars = 'abcdefghijklmnopqrstuvwxyz0123456789';
let result = '';
for (let i = 0; i < length; i++) {
result += chars.charAt(Math.floor(Math.random() * chars.length));
}
return result;
}
function base64ToUint8Array(base64) {
const binaryString = global.atob(base64);
const len = binaryString.length;
const bytes = new Uint8Array(len);
for (let i = 0; i < len; i++) bytes[i] = binaryString.charCodeAt(i);
return bytes;
}
async function importKey(keyString) {
const keyBytes = new TextEncoder().encode(keyString);
return await crypto.subtle.importKey('raw', keyBytes, { name: 'AES-GCM' }, false, ['decrypt']);
}
async function loadAndDecryptQuestions() {
const response = await fetch('questions.encrypted.json');
if (!response.ok) throw new Error('Failed to fetch questions file.');
const encryptedData = await response.json();
const key = await importKey(DECRYPTION_KEY);
const nonce = base64ToUint8Array(encryptedData.nonce);
const ciphertext = base64ToUint8Array(encryptedData.ciphertext);
const tag = base64ToUint8Array(encryptedData.tag);
const fullCiphertext = new Uint8Array(ciphertext.length + tag.length);
fullCiphertext.set(ciphertext);
fullCiphertext.set(tag, ciphertext.length);
const decrypted = await crypto.subtle.decrypt({ name: 'AES-GCM', iv: nonce }, key, fullCiphertext);
const decryptedText = new TextDecoder().decode(decrypted);
return JSON.parse(decryptedText);
}
async function generateFinalHash(username, answer) {
if (!username || !answer) throw new Error('username and answer are required');
const nonce = generateNonce();
const usernameHash = await sha256(username.trim());
const answerHash = await sha256(answer.trim());
const finalHash = await sha256(usernameHash + answerHash + nonce);
const output = `${finalHash}:${nonce}`;
return { output, finalHash, nonce, usernameHash, answerHash };
}
Object.defineProperty(global, 'GitWorkshop', {
value: Object.freeze({ sha256, generateNonce, loadAndDecryptQuestions, generateFinalHash }),
writable: false,
enumerable: true,
configurable: false,
});
})(window);