Skip to content

Commit 2b114e6

Browse files
committed
chore: cache desktop entitlements for offline use
1 parent 938f91f commit 2b114e6

File tree

4 files changed

+369
-77
lines changed

4 files changed

+369
-77
lines changed

src/phoenix/init_vfs.js

Lines changed: 105 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -154,6 +154,111 @@ function _setupVFS(fsLib, pathLib){
154154
});
155155
});
156156
},
157+
/**
158+
* Deletes a file/dir asynchronously. resolves on success or rejects on error.
159+
*
160+
* @function
161+
* @param {string} filePath - The path of the file/dir to be deleted.
162+
* @returns {Promise<Object>} A promise that resolves on success or rejects on error.
163+
*/
164+
unlinkAsync: async function (filePath) {
165+
return new Promise((resolve, reject)=>{
166+
fs.unlink(filePath, (err)=>{
167+
if (err) {
168+
reject(err);
169+
} else {
170+
resolve();
171+
}
172+
});
173+
});
174+
},
175+
/**
176+
* deletes a file/dir asynchronously, always resolves, never rejects.
177+
*
178+
* @function
179+
* @param {string} filePath - The path of the file/dir to be deleted.
180+
* @returns {Promise<Object>} A promise that resolves to an object containing either
181+
* an `error` property if there is an error, or just {} on success.
182+
*/
183+
unlinkResolves: async function (filePath) {
184+
return new Promise((resolve)=>{
185+
fs.unlink(filePath, (error)=>{
186+
if(error){
187+
resolve({error: error});
188+
return;
189+
}
190+
resolve({});
191+
});
192+
});
193+
},
194+
/**
195+
* Reads the contents of a file asynchronously, always resolves, never rejects.
196+
* Mainly use to read config and other files.
197+
* This should not be used for reading project files that are being edited, for that use file system APIs
198+
* as that apis will be able to deal with files being edited in the editor.
199+
*
200+
* @function
201+
* @param {string} filePath - The path of the file to be read.
202+
* @param {string} encoding - The encoding to use for reading the file.
203+
* @returns {Promise<Object>} A promise that resolves to an object containing either
204+
* an `error` property if there is an error, or a `data` property with the file contents.
205+
*/
206+
readFileResolves: function (filePath, encoding) {
207+
return new Promise((resolve)=>{
208+
fs.readFile(filePath, encoding, function (error, data) {
209+
if(error){
210+
resolve({error: error});
211+
return;
212+
}
213+
resolve({data: data});
214+
});
215+
});
216+
},
217+
/**
218+
* Reads the contents of a file asynchronously, resolves with content or rejects with error.
219+
* Mainly use to read config and other files.
220+
* This should not be used for reading project files that are being edited, for that use file system APIs
221+
* as that apis will be able to deal with files being edited in the editor.
222+
*
223+
* @param {string} filePath - The path to the file to be read.
224+
* @param {string} encoding - The encoding format to use when reading the file.
225+
* @returns {Promise<string>} A promise that resolves with the file data when the read is successful,
226+
* or rejects with an error if the read operation fails.
227+
*/
228+
readFileAsync: function (filePath, encoding) {
229+
return new Promise((resolve, reject)=>{
230+
fs.readFile(filePath, encoding, function (error, data) {
231+
if(error){
232+
reject(error);
233+
return;
234+
}
235+
resolve(data);
236+
});
237+
});
238+
},
239+
/**
240+
* Asynchronously writes data to a file, replacing the file if it already exists.
241+
* Mainly use to write config and other files.
242+
* This should not be used for write project files that are being edited, for that use file system APIs
243+
* as that apis will be able to deal with files being edited in the editor.
244+
*
245+
* @param {string} filePath - The path of the file where the data should be written.
246+
* @param {string} content - The data to write into the file.
247+
* @param {string} encoding - The character encoding to use when writing the file.
248+
* @returns {Promise<void>} A promise that resolves when the file has been successfully written,
249+
* or rejects with an error if the operation fails.
250+
*/
251+
writeFileAsync: function (filePath, content, encoding) {
252+
return new Promise((resolve, reject) => {
253+
fs.writeFile(filePath, content, encoding, (err) => {
254+
if (err) {
255+
reject(err);
256+
} else {
257+
resolve();
258+
}
259+
});
260+
});
261+
},
157262
fs: fsLib,
158263
path: pathLib
159264
};

src/phoenix/trust_ring.js

Lines changed: 57 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -182,26 +182,6 @@ const CRED_KEY_API = Phoenix.isTestWindow ? "API_KEY_TEST" : "API_KEY";
182182
const CRED_KEY_PROMO = Phoenix.isTestWindow ? "PROMO_GRANT_KEY_TEST" : "PROMO_GRANT_KEY";
183183
const SIGNATURE_SALT_KEY = Phoenix.isTestWindow ? "SIGNATURE_SALT_KEY_TEST" : "SIGNATURE_SALT_KEY";
184184
const { key, iv } = _selectKeys();
185-
// this key is set at boot time as a truct base for all the core components before any extensions are loaded.
186-
// just before extensions are loaded, this key is blanked. This can be used by core modules to talk with other
187-
// core modules securely without worrying about interception by extensions.
188-
// KernalModeTrust should only be available within all code that loads before the first default/any extension.
189-
window.KernalModeTrust = {
190-
CRED_KEY_API,
191-
CRED_KEY_PROMO,
192-
SIGNATURE_SALT_KEY,
193-
aesKeys: { key, iv },
194-
setCredential,
195-
getCredential,
196-
removeCredential,
197-
AESDecryptString,
198-
generateRandomKeyAndIV,
199-
dismantleKeyring
200-
};
201-
if(Phoenix.isSpecRunnerWindow){
202-
window.specRunnerTestKernalModeTrust = window.KernalModeTrust;
203-
}
204-
// key is 64 hex characters, iv is 24 hex characters
205185

206186
async function setCredential(credKey, secret) {
207187
if(!window.__TAURI__){
@@ -260,5 +240,62 @@ export async function initTrustRing() {
260240
if(!window.__TAURI__){
261241
return;
262242
}
243+
// this will only work once in a window unless dismantleKeyring is called. So this is safe as
244+
// a public export as essentially this is a fn that only works in the boot and shutdown phase.
263245
await window.__TAURI__.tauri.invoke("trust_window_aes_key", {key, iv});
264246
}
247+
248+
/**
249+
* Generates an SHA-256 hash signature of the provided data string combined with a salt.
250+
*
251+
* @param {string} dataString - The input data string that needs to be signed.
252+
* @param {string} salt - A salt value to combine with the data string for additional uniqueness.
253+
* @return {Promise<string>} A promise that resolves to the generated SHA-256 hash signature as a hexadecimal string.
254+
*/
255+
async function generateDataSignature(dataString, salt) {
256+
const signatureData = dataString + "|" + salt;
257+
const encoder = new TextEncoder();
258+
const dataBuffer = encoder.encode(signatureData);
259+
const hashBuffer = await crypto.subtle.digest('SHA-256', dataBuffer);
260+
const hashArray = Array.from(new Uint8Array(hashBuffer));
261+
return hashArray.map(b => b.toString(16).padStart(2, '0')).join('');
262+
}
263+
264+
/**
265+
* Validates the provided data signature by comparing it to an expected signature.
266+
*
267+
* @param {string} data - The data to validate the signature against.
268+
* @param {string} signature - The actual signature to be validated.
269+
* @param {string} salt - The salt used in generating the expected signature.
270+
* @return {Promise<boolean>} A promise resolving to true if the signature is valid, otherwise false.
271+
*/
272+
async function validateDataSignature(data, signature, salt) {
273+
if (!data || !signature) {
274+
return false;
275+
}
276+
const expectedSignature = await generateDataSignature(data, salt);
277+
return signature === expectedSignature;
278+
}
279+
280+
// this key is set at boot time as a trust base for all the core components before any extensions are loaded.
281+
// just before extensions are loaded, this key is blanked. This can be used by core modules to talk with other
282+
// core modules securely without worrying about interception by extensions.
283+
// KernalModeTrust should only be available within all code that loads before the first default/any extension.
284+
window.KernalModeTrust = {
285+
CRED_KEY_API,
286+
CRED_KEY_PROMO,
287+
SIGNATURE_SALT_KEY,
288+
aesKeys: { key, iv },
289+
setCredential,
290+
getCredential,
291+
removeCredential,
292+
AESDecryptString,
293+
generateRandomKeyAndIV,
294+
dismantleKeyring,
295+
generateDataSignature,
296+
validateDataSignature
297+
};
298+
if(Phoenix.isSpecRunnerWindow){
299+
window.specRunnerTestKernalModeTrust = window.KernalModeTrust;
300+
}
301+
// key is 64 hex characters, iv is 24 hex characters

0 commit comments

Comments
 (0)