@@ -16,13 +16,13 @@ import * as StorageAccess from "../StorageAccess";
1616 */
1717
1818/*
19- * Keys used when storing the tokens in indexeddb or localstorage
19+ * Names used when storing the tokens in indexeddb or localstorage
2020 */
2121export const ACCESS_TOKEN_STORAGE_KEY = "mx_access_token" ;
2222export const REFRESH_TOKEN_STORAGE_KEY = "mx_refresh_token" ;
2323/*
24- * Used as initialization vector during encryption in persistTokenInStorage
25- * And decryption in restoreFromLocalStorage
24+ * Names of the tokens. Used as part of the calculation to derive AES keys during encryption in persistTokenInStorage,
25+ * and decryption in restoreSessionFromStorage.
2626 */
2727export const ACCESS_TOKEN_IV = "access_token" ;
2828export const REFRESH_TOKEN_IV = "refresh_token" ;
@@ -60,50 +60,63 @@ async function pickleKeyToAesKey(pickleKey: string): Promise<Uint8Array> {
6060 ) ;
6161}
6262
63- const isEncryptedPayload = ( token ?: IEncryptedPayload | string | undefined ) : token is IEncryptedPayload => {
64- return ! ! token && typeof token !== "string" ;
65- } ;
6663/**
6764 * Try to decrypt a token retrieved from storage
68- * Where token is not encrypted (plain text) returns the plain text token
69- * Where token is encrypted, attempts decryption. Returns successfully decrypted token, else undefined.
70- * @param pickleKey pickle key used during encryption of token, or undefined
71- * @param token
72- * @param tokenIv initialization vector used during encryption of token eg ACCESS_TOKEN_IV
73- * @returns the decrypted token, or the plain text token. Returns undefined when token cannot be decrypted
65+ *
66+ * Where token is not encrypted (plain text) returns the plain text token.
67+ *
68+ * Where token is encrypted, attempts decryption. Returns successfully decrypted token, or throws if
69+ * decryption failed.
70+ *
71+ * @param pickleKey Pickle key: used to derive the encryption key, or undefined if the token is not encrypted.
72+ * Must be the same as provided to {@link persistTokenInStorage}.
73+ * @param token token to be decrypted.
74+ * @param tokenName Name of the token. Used in logging, but also used as an input when generating the actual AES key,
75+ * so the same value must be provided to {@link persistTokenInStorage}.
76+ *
77+ * @returns the decrypted token, or the plain text token.
7478 */
7579export async function tryDecryptToken (
7680 pickleKey : string | undefined ,
77- token : IEncryptedPayload | string | undefined ,
78- tokenIv : string ,
79- ) : Promise < string | undefined > {
80- if ( pickleKey && isEncryptedPayload ( token ) ) {
81- const encrKey = await pickleKeyToAesKey ( pickleKey ) ;
82- const decryptedToken = await decryptAES ( token , encrKey , tokenIv ) ;
83- encrKey . fill ( 0 ) ;
84- return decryptedToken ;
85- }
86- // if the token wasn't encrypted (plain string) just return it back
81+ token : IEncryptedPayload | string ,
82+ tokenName : string ,
83+ ) : Promise < string > {
8784 if ( typeof token === "string" ) {
85+ // Looks like an unencrypted token
8886 return token ;
8987 }
90- // otherwise return undefined
88+
89+ // Otherwise, it must be an encrypted token.
90+ if ( ! pickleKey ) {
91+ throw new Error ( `Error decrypting secret ${ tokenName } : no pickle key found.` ) ;
92+ }
93+
94+ const encrKey = await pickleKeyToAesKey ( pickleKey ) ;
95+ const decryptedToken = await decryptAES ( token , encrKey , tokenName ) ;
96+ encrKey . fill ( 0 ) ;
97+ return decryptedToken ;
9198}
9299
93100/**
94101 * Persist a token in storage
95- * When pickle key is present, will attempt to encrypt the token
96- * Stores in idb, falling back to localStorage
97102 *
98- * @param storageKey key used to store the token
99- * @param initializationVector Initialization vector for encrypting the token. Only used when `pickleKey` is present
100- * @param token the token to store, when undefined any existing token at the storageKey is removed from storage
101- * @param pickleKey optional pickle key used to encrypt token
102- * @param hasTokenStorageKey Localstorage key for an item which stores whether we expect to have a token in indexeddb, eg "mx_has_access_token".
103+ * When pickle key is present, will attempt to encrypt the token. If encryption fails (typically because
104+ * WebCrypto is unavailable), the key will be stored unencrypted.
105+ *
106+ * Stores in IndexedDB, falling back to localStorage.
107+ *
108+ * @param storageKey key used to store the token. Note: not an encryption key; rather a localstorage or indexeddb key.
109+ * @param tokenName Name of the token. Used in logging, but also used as an input when generating the actual AES key,
110+ * so the same value must be provided to {@link tryDecryptToken} when decrypting.
111+ * @param token the token to store. When undefined, any existing token at the `storageKey` is removed from storage.
112+ * @param pickleKey Pickle key: used to derive the key used to encrypt token. If `undefined`, the token will be stored
113+ * unencrypted.
114+ * @param hasTokenStorageKey Localstorage key for an item which stores whether we expect to have a token in indexeddb,
115+ * eg "mx_has_access_token".
103116 */
104117export async function persistTokenInStorage (
105118 storageKey : string ,
106- initializationVector : string ,
119+ tokenName : string ,
107120 token : string | undefined ,
108121 pickleKey : string | undefined ,
109122 hasTokenStorageKey : string ,
@@ -122,12 +135,12 @@ export async function persistTokenInStorage(
122135 try {
123136 // try to encrypt the access token using the pickle key
124137 const encrKey = await pickleKeyToAesKey ( pickleKey ) ;
125- encryptedToken = await encryptAES ( token , encrKey , initializationVector ) ;
138+ encryptedToken = await encryptAES ( token , encrKey , tokenName ) ;
126139 encrKey . fill ( 0 ) ;
127140 } catch ( e ) {
128141 // This is likely due to the browser not having WebCrypto or somesuch.
129142 // Warn about it, but fall back to storing the unencrypted token.
130- logger . warn ( `Could not encrypt token for ${ storageKey } ` , e ) ;
143+ logger . warn ( `Could not encrypt token for ${ tokenName } ` , e ) ;
131144 }
132145 }
133146 try {
@@ -159,9 +172,11 @@ export async function persistTokenInStorage(
159172}
160173
161174/**
162- * Wraps persistTokenInStorage with accessToken storage keys
163- * @param token the token to store, when undefined any existing accessToken is removed from storage
164- * @param pickleKey optional pickle key used to encrypt token
175+ * Wraps {@link persistTokenInStorage} with accessToken storage keys
176+ *
177+ * @param token - The token to store. When undefined, any existing accessToken is removed from storage.
178+ * @param pickleKey - Pickle key: used to derive the key used to encrypt token. If `undefined`, the token will be stored
179+ * unencrypted.
165180 */
166181export async function persistAccessTokenInStorage (
167182 token : string | undefined ,
@@ -177,9 +192,11 @@ export async function persistAccessTokenInStorage(
177192}
178193
179194/**
180- * Wraps persistTokenInStorage with refreshToken storage keys
181- * @param token the token to store, when undefined any existing refreshToken is removed from storage
182- * @param pickleKey optional pickle key used to encrypt token
195+ * Wraps {@link persistTokenInStorage} with refreshToken storage keys.
196+ *
197+ * @param token - The token to store. When undefined, any existing refreshToken is removed from storage.
198+ * @param pickleKey - Pickle key: used to derive the key used to encrypt token. If `undefined`, the token will be stored
199+ * unencrypted.
183200 */
184201export async function persistRefreshTokenInStorage (
185202 token : string | undefined ,
0 commit comments