mirror of
https://github.com/johannesjo/super-productivity.git
synced 2026-07-18 00:46:45 +00:00
fix(dropbox): use hash-wasm fallback for PKCE on Android
On Android, Capacitor serves the app from http://localhost which is not a secure context. WebCrypto's crypto.subtle API is unavailable in insecure contexts, causing Dropbox OAuth PKCE code generation to fail. Use hash-wasm (already a dependency for Argon2id) as fallback when crypto.subtle is unavailable.
This commit is contained in:
parent
3fc0be6924
commit
e2c585ee45
2 changed files with 34 additions and 12 deletions
|
|
@ -29,8 +29,8 @@ describe('generatePKCECodes', () => {
|
|||
);
|
||||
});
|
||||
|
||||
it('should throw error when crypto.subtle is unavailable', async () => {
|
||||
// Mock crypto with getRandomValues but without subtle
|
||||
it('should successfully generate PKCE codes when crypto.subtle is unavailable (fallback)', async () => {
|
||||
// Mock crypto with getRandomValues but without subtle (simulates Android Capacitor insecure context)
|
||||
Object.defineProperty(window, 'crypto', {
|
||||
value: {
|
||||
getRandomValues: (array: Uint32Array) => {
|
||||
|
|
@ -46,9 +46,17 @@ describe('generatePKCECodes', () => {
|
|||
configurable: true,
|
||||
});
|
||||
|
||||
await expectAsync(generatePKCECodes(128)).toBeRejectedWithError(
|
||||
/WebCrypto API.*subtle/i,
|
||||
);
|
||||
const result = await generatePKCECodes(128);
|
||||
|
||||
expect(result).toBeDefined();
|
||||
expect(result.codeVerifier).toBeDefined();
|
||||
expect(result.codeChallenge).toBeDefined();
|
||||
expect(typeof result.codeVerifier).toBe('string');
|
||||
expect(typeof result.codeChallenge).toBe('string');
|
||||
expect(result.codeVerifier.length).toBeGreaterThan(0);
|
||||
expect(result.codeChallenge.length).toBeGreaterThan(0);
|
||||
// Code challenge should be different from verifier (it's hashed)
|
||||
expect(result.codeChallenge).not.toBe(result.codeVerifier);
|
||||
});
|
||||
|
||||
it('should successfully generate PKCE codes when WebCrypto is available', async () => {
|
||||
|
|
|
|||
|
|
@ -1,4 +1,14 @@
|
|||
// taken from https://github.com/aaronpk/pkce-vanilla-js/blob/master/index.html
|
||||
import { sha256 as hashWasmSha256 } from 'hash-wasm';
|
||||
|
||||
// Convert hex string to ArrayBuffer (needed for hash-wasm fallback)
|
||||
const hexStringToArrayBuffer = (hex: string): ArrayBuffer => {
|
||||
const bytes = new Uint8Array(hex.length / 2);
|
||||
for (let i = 0; i < hex.length; i += 2) {
|
||||
bytes[i / 2] = parseInt(hex.substr(i, 2), 16);
|
||||
}
|
||||
return bytes.buffer;
|
||||
};
|
||||
|
||||
// Generate a secure random string using the browser crypto functions
|
||||
const generateRandomString = (length: number): string => {
|
||||
|
|
@ -15,18 +25,22 @@ const generateRandomString = (length: number): string => {
|
|||
|
||||
// Calculate the SHA256 hash of the input text.
|
||||
// Returns a promise that resolves to an ArrayBuffer
|
||||
const sha256 = (plain: string): Promise<ArrayBuffer> => {
|
||||
const sha256 = async (plain: string): Promise<ArrayBuffer> => {
|
||||
const encoder = new TextEncoder();
|
||||
const data = encoder.encode(plain);
|
||||
// NOTE: crypto.subtle is supposed to be undefined in insecure contexts
|
||||
|
||||
// Use WebCrypto if available (secure context)
|
||||
// NOTE: crypto.subtle is undefined in insecure contexts (e.g., Android Capacitor http://localhost)
|
||||
// @see https://www.chromium.org/blink/webcrypto
|
||||
if (window.crypto?.subtle === undefined) {
|
||||
throw new Error(
|
||||
'WebCrypto API (subtle.digest) is only supported in secure contexts.',
|
||||
);
|
||||
if (window.crypto?.subtle !== undefined) {
|
||||
return window.crypto.subtle.digest('SHA-256', data);
|
||||
}
|
||||
|
||||
return window.crypto.subtle.digest('SHA-256', data);
|
||||
// Fallback to hash-wasm for insecure contexts (e.g., Android Capacitor serves from http://localhost)
|
||||
// We can't use WebCrypto in insecure contexts, so we use hash-wasm which is already a dependency
|
||||
// (used for Argon2id encryption) and provides a pure WebAssembly implementation
|
||||
const hexHash = await hashWasmSha256(data);
|
||||
return hexStringToArrayBuffer(hexHash);
|
||||
};
|
||||
|
||||
// Base64-urlencodes the input string
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue