initial commit

This commit is contained in:
Walter Oggioni
2024-02-14 08:38:15 +08:00
parent 911419f30a
commit 336e4e8360
6 changed files with 325 additions and 0 deletions

109
sspoc/static/js/sspoc.js Normal file
View File

@@ -0,0 +1,109 @@
function integerToBytes(integer, numBytes) {
const bytesArray = new Array(numBytes).fill(0);
for (let i = 0; i < numBytes; i++) {
bytesArray[numBytes - i - 1] = integer & 0xff;
integer >>= 8;
}
return Uint8Array.from(bytesArray);
}
function concatenateUInt8Arrays(array1, array2) {
const newArray = new Uint8Array(array1.length + array2.length);
newArray.set(array1);
newArray.set(array2, array1.length);
return newArray;
}
/*
Convert an ArrayBuffer into a string
from https://developer.chrome.com/blog/how-to-convert-arraybuffer-to-and-from-string/
*/
function ab2str(buf) {
return String.fromCharCode.apply(null, new Uint8Array(buf));
}
/*
Export the given key and write it into the "exported-key" space.
*/
async function exportCryptoKeyPem(key) {
const exported = await window.crypto.subtle.exportKey("spki", key);
const exportedAsString = ab2str(exported);
const exportedAsBase64 = btoa(exportedAsString);
return exportedAsBase64;
}
async function exportCryptoKey(key) {
const exported = await window.crypto.subtle.exportKey("jwk", key);
return JSON.stringify(exported, null, " ");
}
async function createKeyPair() {
const crypto = window.crypto.subtle
const keyPair = await window.crypto.subtle.generateKey(
{
name: "RSA-OAEP",
modulusLength: 2048,
publicExponent: new Uint8Array([4, 0, 1]),
hash: "SHA-256",
},
true,
["encrypt", "decrypt"]
);
return keyPair;
}
let keyPair = createKeyPair();
let loginForm = document.getElementById('login-form');
let loginButton = document.getElementById('login-button');
let nonce = null
loginButton.addEventListener('click', async evt => {
const publicKey = (await keyPair).publicKey;
const publicKeyPem = await exportCryptoKeyPem(publicKey);
fetch('api/login', {
method: 'POST',
headers: {
'public-key' : publicKeyPem,
'Content-Type': 'application/json'
},
body: JSON.stringify({ username: loginForm.username.value, password: loginForm.password.value})
}).then(async response => {
const nonceHeader = response.headers.get('nonce');
const encryptedNonce = atob(nonceHeader);
const privateKey = (await keyPair).privateKey;
const crypto = window.crypto.subtle;
const encryptedBuffer = Uint8Array.from(atob(nonceHeader), c => c.charCodeAt(0));
nonce = await crypto.decrypt({ name: "RSA-OAEP" }, privateKey, encryptedBuffer)
.then(it => new Uint8Array(it));
return response.text();
}).then(text => {
let paragraph = document.createElement('p');
paragraph.textContent = text;
document.body.appendChild(paragraph);
});
});
let button = document.createElement('button');
button.textContent = 'Press me'
document.body.appendChild(button);
button.addEventListener('click', async evt => {
let header = {};
if(nonce != null) {
const crypto = window.crypto.subtle;
const epochTick = Math.floor(new Date().getTime() / 10000)
const data = concatenateUInt8Arrays(nonce, integerToBytes(epochTick, 8))
const hash = new Uint8Array(await crypto.digest("SHA-256", data));
const token = btoa(Array.from(hash, byte => String.fromCharCode(byte)).join(''));
headers = {
'x-token': token
};
}
fetch('api/hello', {
method: 'GET',
headers
}).then(response => response.text()).then(text => {
let paragraph = document.createElement('p');
paragraph.textContent = text;
document.body.appendChild(paragraph);
});
});