forked from phcode-dev/staging.phcode.dev
-
Notifications
You must be signed in to change notification settings - Fork 1
Expand file tree
/
Copy pathtrust_ring.js
More file actions
1 lines (1 loc) · 8.37 KB
/
Copy pathtrust_ring.js
File metadata and controls
1 lines (1 loc) · 8.37 KB
1
function generateRandomKeyAndIV(){const keyBytes=new Uint8Array(32);crypto.getRandomValues(keyBytes);const ivBytes=new Uint8Array(12);crypto.getRandomValues(ivBytes);const key=Array.from(keyBytes).map(byte=>byte.toString(16).padStart(2,"0")).join(""),iv=Array.from(ivBytes).map(byte=>byte.toString(16).padStart(2,"0")).join("");return{key:key,iv:iv}}async function AESEncryptString(val,key,iv){const data=(new TextEncoder).encode(val),keyBytes=new Uint8Array(key.length/2);for(let i=0;i<key.length;i+=2)keyBytes[i/2]=parseInt(key.substr(i,2),16);const ivBytes=new Uint8Array(iv.length/2);for(let i=0;i<iv.length;i+=2)ivBytes[i/2]=parseInt(iv.substr(i,2),16);const cryptoKey=await crypto.subtle.importKey("raw",keyBytes,{name:"AES-GCM"},!1,["encrypt"]),encryptedBuffer=await crypto.subtle.encrypt({name:"AES-GCM",iv:ivBytes},cryptoKey,data);return Array.from(new Uint8Array(encryptedBuffer)).map(byte=>byte.toString(16).padStart(2,"0")).join("")}async function AESDecryptString(val,key,iv){const encryptedData=new Uint8Array(val.length/2);for(let i=0;i<val.length;i+=2)encryptedData[i/2]=parseInt(val.substr(i,2),16);const keyBytes=new Uint8Array(key.length/2);for(let i=0;i<key.length;i+=2)keyBytes[i/2]=parseInt(key.substr(i,2),16);const ivBytes=new Uint8Array(iv.length/2);for(let i=0;i<iv.length;i+=2)ivBytes[i/2]=parseInt(iv.substr(i,2),16);const cryptoKey=await crypto.subtle.importKey("raw",keyBytes,{name:"AES-GCM"},!1,["decrypt"]),decryptedBuffer=await crypto.subtle.decrypt({name:"AES-GCM",iv:ivBytes},cryptoKey,encryptedData);return new TextDecoder("utf-8").decode(decryptedBuffer)}const TEMP_KV_TRUST_FOR_TESTSUITE="TEMP_KV_TRUST_FOR_TESTSUITE";function _selectKeys(){if(Phoenix.isTestWindow){const kvj=window.top.sessionStorage.getItem(TEMP_KV_TRUST_FOR_TESTSUITE);if(!kvj){const kv=generateRandomKeyAndIV();return window.top.sessionStorage.setItem(TEMP_KV_TRUST_FOR_TESTSUITE,JSON.stringify(kv)),kv}try{return JSON.parse(kvj)}catch(e){console.error("Error parsing test suite trust keyring, defaulting to random which may not work!",e)}}return generateRandomKeyAndIV()}const CRED_KEY_API=Phoenix.isTestWindow?"API_KEY_TEST":"API_KEY",CRED_KEY_PROMO=Phoenix.isTestWindow?"PROMO_GRANT_KEY_TEST":"PROMO_GRANT_KEY",SIGNATURE_SALT_KEY=Phoenix.isTestWindow?"SIGNATURE_SALT_KEY_TEST":"SIGNATURE_SALT_KEY",VERSION_PORTER_KEY=Phoenix.isTestWindow?"VERSION_PORTER_TEST":"VERSION_PORTER",{key:key,iv:iv}=_selectKeys();let _trustRingReadyResolve,_trustRingReady=new Promise(resolve=>{_trustRingReadyResolve=resolve});async function setCredential(credKey,secret){if(await _trustRingReady,!window.__IS_NATIVE_SHELL__)throw new Error("Phoenix API key can only be set in native shell!");if(!credKey)throw new Error("credKey is required to set credential!");return window.__TAURI__?window.__TAURI__.tauri.invoke("store_credential",{scopeName:credKey,secretVal:secret}):window.__ELECTRON__?window.electronAPI.storeCredential(credKey,secret):void 0}async function getCredential(credKey){if(await _trustRingReady,!window.__IS_NATIVE_SHELL__)throw new Error("Phoenix API key can only be get in native shell!");if(!credKey)throw new Error("credKey is required to get credential!");let encryptedKey;return window.__TAURI__?encryptedKey=await window.__TAURI__.tauri.invoke("get_credential",{scopeName:credKey}):window.__ELECTRON__&&(encryptedKey=await window.electronAPI.getCredential(credKey)),encryptedKey?AESDecryptString(encryptedKey,key,iv):null}async function removeCredential(credKey){if(await _trustRingReady,!window.__IS_NATIVE_SHELL__)throw new Error("Phoenix API key can only be removed in native shell!");if(!credKey)throw new Error("credKey is required to remove credential!");return window.__TAURI__?window.__TAURI__.tauri.invoke("delete_credential",{scopeName:credKey}):window.__ELECTRON__?window.electronAPI.deleteCredential(credKey):void 0}let _dismatled=!1;async function dismantleKeyring(){if(await _trustRingReady,_dismatled)throw new Error("Keyring can only be dismantled once!");if(_dismatled=!0,!key||!iv)return void console.error("Invalid kernal keys supplied to shutdown. Ignoring kernal trust reset at shutdown.");if(!window.__IS_NATIVE_SHELL__)return;let result;return window.__TAURI__?result=await window.__TAURI__.tauri.invoke("remove_trust_window_aes_key",{key:key,iv:iv}):window.__ELECTRON__&&(result=await window.electronAPI.removeTrustWindowAesKey(key,iv)),_trustRingReady=new Promise(resolve=>{_trustRingReadyResolve=resolve}),result}export async function initTrustRing(){if(window.__IS_NATIVE_SHELL__){try{window.__TAURI__?await window.__TAURI__.tauri.invoke("trust_window_aes_key",{key:key,iv:iv}):window.__ELECTRON__&&await window.electronAPI.trustWindowAesKey(key,iv)}catch(e){window.logger&&window.logger.reportError(e,"Error establishing trust ring");const Metrics=window.Metrics;Metrics&&Metrics.countEvent(Metrics.EVENT_TYPE.ERROR,"trustRing","initFailed")}_trustRingReadyResolve(),await _portCredentials()}else _trustRingReadyResolve()}async function reinstallCreds(){if(!window.__IS_NATIVE_SHELL__)throw new Error("reinstallCreds can only be called in native shell!");const apiKey=await getCredential(CRED_KEY_API),promoKey=await getCredential(CRED_KEY_PROMO),saltKey=await getCredential(SIGNATURE_SALT_KEY);apiKey&&await removeCredential(CRED_KEY_API),promoKey&&await removeCredential(CRED_KEY_PROMO),saltKey&&await removeCredential(SIGNATURE_SALT_KEY),apiKey&&await setCredential(CRED_KEY_API,apiKey),promoKey&&await setCredential(CRED_KEY_PROMO,promoKey),saltKey&&await setCredential(SIGNATURE_SALT_KEY,saltKey);const currentVersion=Phoenix.metadata.version;await setCredential(VERSION_PORTER_KEY,currentVersion)}async function _portCredentials(){if(Phoenix.isNativeApp&&"win"!==Phoenix.platform&&"linux"!==Phoenix.platform)try{const storedVersion=await getCredential(VERSION_PORTER_KEY),currentVersion=Phoenix.metadata.version;!storedVersion&¤tVersion?await setCredential(VERSION_PORTER_KEY,currentVersion):storedVersion&¤tVersion&&storedVersion!==currentVersion&&(console.log(`Version changed from ${storedVersion} to ${currentVersion}, reinstalling credentials`),await setCredential(VERSION_PORTER_KEY,currentVersion),await reinstallCreds())}catch(error){console.error("Error during version-based credential check:",error)}}const FALLBACK_SALT="fallback-salt-2f309322-b32d-4d59-85b4-2baef666a9f4";let currentSalt;async function _getTrustedKeyInternal(){try{let salt=await getCredential(SIGNATURE_SALT_KEY);return salt||(salt=crypto.randomUUID(),await setCredential(SIGNATURE_SALT_KEY,salt)),salt}catch(error){return console.error("Error in _getTrustedKeyInternal:",error),null}}const MAX_SALT_RETRIES=2;async function getTrustedKey(){if(currentSalt)return currentSalt;if(Phoenix.isNativeApp){let salt=await _getTrustedKeyInternal();const Metrics=window.Metrics;for(let i=0;i<MAX_SALT_RETRIES&&!salt;i++)console.warn(`Retrying _getTrustedKeyInternal (attempt ${i+2})`),Metrics&&Metrics.countEvent(Metrics.EVENT_TYPE.AUTH,"saltGet","retry"),salt=await _getTrustedKeyInternal();return salt?(currentSalt=salt,salt):(console.error("All salt retrieval attempts failed, using fallback salt"),Metrics&&Metrics.countEvent(Metrics.EVENT_TYPE.AUTH,"saltGet","Err"),currentSalt=FALLBACK_SALT,FALLBACK_SALT)}return currentSalt=FALLBACK_SALT,FALLBACK_SALT}async function generateDataSignature(dataString,salt){const signatureData=salt?dataString+"|"+salt:dataString,encoder=new TextEncoder,dataBuffer=encoder.encode(signatureData),hashBuffer=await crypto.subtle.digest("SHA-256",dataBuffer),hashArray=Array.from(new Uint8Array(hashBuffer));return hashArray.map(b=>b.toString(16).padStart(2,"0")).join("")}async function validateDataSignature(data,signature,salt){if(!signature)return!1;const expectedSignature=await generateDataSignature(data,salt);return signature===expectedSignature}window.KernalModeTrust={CRED_KEY_API:CRED_KEY_API,CRED_KEY_PROMO:CRED_KEY_PROMO,SIGNATURE_SALT_KEY:SIGNATURE_SALT_KEY,aesKeys:{key:key,iv:iv},setCredential:setCredential,getCredential:getCredential,removeCredential:removeCredential,AESEncryptString:AESEncryptString,AESDecryptString:AESDecryptString,generateRandomKeyAndIV:generateRandomKeyAndIV,dismantleKeyring:dismantleKeyring,generateDataSignature:generateDataSignature,validateDataSignature:validateDataSignature,reinstallCreds:reinstallCreds,getTrustedKey:getTrustedKey},window._phoenixBuilder&&window._phoenixBuilder.setKernalModeTrust&&window._phoenixBuilder.setKernalModeTrust(window.KernalModeTrust),Phoenix.isSpecRunnerWindow&&(window.specRunnerTestKernalModeTrust=window.KernalModeTrust);