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
105 changes: 105 additions & 0 deletions src/phoenix/init_vfs.js
Original file line number Diff line number Diff line change
Expand Up @@ -154,6 +154,111 @@ function _setupVFS(fsLib, pathLib){
});
});
},
/**
* Deletes a file/dir asynchronously. resolves on success or rejects on error.
*
* @function
* @param {string} filePath - The path of the file/dir to be deleted.
* @returns {Promise<Object>} A promise that resolves on success or rejects on error.
*/
unlinkAsync: async function (filePath) {
return new Promise((resolve, reject)=>{
fs.unlink(filePath, (err)=>{
if (err) {
reject(err);
} else {
resolve();
}
});
});
},
/**
* deletes a file/dir asynchronously, always resolves, never rejects.
*
* @function
* @param {string} filePath - The path of the file/dir to be deleted.
* @returns {Promise<Object>} A promise that resolves to an object containing either
* an `error` property if there is an error, or just {} on success.
*/
unlinkResolves: async function (filePath) {
return new Promise((resolve)=>{
fs.unlink(filePath, (error)=>{
if(error){
resolve({error: error});
return;
}
resolve({});
});
});
},
/**
* Reads the contents of a file asynchronously, always resolves, never rejects.
* Mainly use to read config and other files.
* This should not be used for reading project files that are being edited, for that use file system APIs
* as that apis will be able to deal with files being edited in the editor.
*
* @function
* @param {string} filePath - The path of the file to be read.
* @param {string} encoding - The encoding to use for reading the file.
* @returns {Promise<Object>} A promise that resolves to an object containing either
* an `error` property if there is an error, or a `data` property with the file contents.
*/
readFileResolves: function (filePath, encoding) {
return new Promise((resolve)=>{
fs.readFile(filePath, encoding, function (error, data) {
if(error){
resolve({error: error});
return;
}
resolve({data: data});
});
});
},
/**
* Reads the contents of a file asynchronously, resolves with content or rejects with error.
* Mainly use to read config and other files.
* This should not be used for reading project files that are being edited, for that use file system APIs
* as that apis will be able to deal with files being edited in the editor.
*
* @param {string} filePath - The path to the file to be read.
* @param {string} encoding - The encoding format to use when reading the file.
* @returns {Promise<string>} A promise that resolves with the file data when the read is successful,
* or rejects with an error if the read operation fails.
*/
readFileAsync: function (filePath, encoding) {
return new Promise((resolve, reject)=>{
fs.readFile(filePath, encoding, function (error, data) {
if(error){
reject(error);
return;
}
resolve(data);
});
});
},
/**
* Asynchronously writes data to a file, replacing the file if it already exists.
* Mainly use to write config and other files.
* This should not be used for write project files that are being edited, for that use file system APIs
* as that apis will be able to deal with files being edited in the editor.
*
* @param {string} filePath - The path of the file where the data should be written.
* @param {string} content - The data to write into the file.
* @param {string} encoding - The character encoding to use when writing the file.
* @returns {Promise<void>} A promise that resolves when the file has been successfully written,
* or rejects with an error if the operation fails.
*/
writeFileAsync: function (filePath, content, encoding) {
return new Promise((resolve, reject) => {
fs.writeFile(filePath, content, encoding, (err) => {
if (err) {
reject(err);
} else {
resolve();
}
});
});
},
fs: fsLib,
path: pathLib
};
Expand Down
77 changes: 57 additions & 20 deletions src/phoenix/trust_ring.js
Original file line number Diff line number Diff line change
Expand Up @@ -182,26 +182,6 @@ const CRED_KEY_API = Phoenix.isTestWindow ? "API_KEY_TEST" : "API_KEY";
const CRED_KEY_PROMO = Phoenix.isTestWindow ? "PROMO_GRANT_KEY_TEST" : "PROMO_GRANT_KEY";
const SIGNATURE_SALT_KEY = Phoenix.isTestWindow ? "SIGNATURE_SALT_KEY_TEST" : "SIGNATURE_SALT_KEY";
const { key, iv } = _selectKeys();
// this key is set at boot time as a truct base for all the core components before any extensions are loaded.
// just before extensions are loaded, this key is blanked. This can be used by core modules to talk with other
// core modules securely without worrying about interception by extensions.
// KernalModeTrust should only be available within all code that loads before the first default/any extension.
window.KernalModeTrust = {
CRED_KEY_API,
CRED_KEY_PROMO,
SIGNATURE_SALT_KEY,
aesKeys: { key, iv },
setCredential,
getCredential,
removeCredential,
AESDecryptString,
generateRandomKeyAndIV,
dismantleKeyring
};
if(Phoenix.isSpecRunnerWindow){
window.specRunnerTestKernalModeTrust = window.KernalModeTrust;
}
// key is 64 hex characters, iv is 24 hex characters

async function setCredential(credKey, secret) {
if(!window.__TAURI__){
Expand Down Expand Up @@ -260,5 +240,62 @@ export async function initTrustRing() {
if(!window.__TAURI__){
return;
}
// this will only work once in a window unless dismantleKeyring is called. So this is safe as
// a public export as essentially this is a fn that only works in the boot and shutdown phase.
await window.__TAURI__.tauri.invoke("trust_window_aes_key", {key, iv});
}

/**
* Generates an SHA-256 hash signature of the provided data string combined with a salt.
*
* @param {string} dataString - The input data string that needs to be signed.
* @param {string} salt - A salt value to combine with the data string for additional uniqueness.
* @return {Promise<string>} A promise that resolves to the generated SHA-256 hash signature as a hexadecimal string.
*/
async function generateDataSignature(dataString, salt) {
const signatureData = dataString + "|" + salt;
const encoder = new TextEncoder();
const dataBuffer = encoder.encode(signatureData);
const hashBuffer = await crypto.subtle.digest('SHA-256', dataBuffer);
const hashArray = Array.from(new Uint8Array(hashBuffer));
return hashArray.map(b => b.toString(16).padStart(2, '0')).join('');
}

/**
* Validates the provided data signature by comparing it to an expected signature.
*
* @param {string} data - The data to validate the signature against.
* @param {string} signature - The actual signature to be validated.
* @param {string} salt - The salt used in generating the expected signature.
* @return {Promise<boolean>} A promise resolving to true if the signature is valid, otherwise false.
*/
async function validateDataSignature(data, signature, salt) {
if (!signature) {
return false;
}
const expectedSignature = await generateDataSignature(data, salt);
return signature === expectedSignature;
}

// this key is set at boot time as a trust base for all the core components before any extensions are loaded.
// just before extensions are loaded, this key is blanked. This can be used by core modules to talk with other
// core modules securely without worrying about interception by extensions.
// KernalModeTrust should only be available within all code that loads before the first default/any extension.
window.KernalModeTrust = {
CRED_KEY_API,
CRED_KEY_PROMO,
SIGNATURE_SALT_KEY,
aesKeys: { key, iv },
setCredential,
getCredential,
removeCredential,
AESDecryptString,
generateRandomKeyAndIV,
dismantleKeyring,
generateDataSignature,
validateDataSignature
};
if(Phoenix.isSpecRunnerWindow){
window.specRunnerTestKernalModeTrust = window.KernalModeTrust;
}
// key is 64 hex characters, iv is 24 hex characters
Loading
Loading