in src/core/swa-cli-persistence-plugin/impl/credentials-store.ts [81:137]
async setPassword(service: string, account: string, credentials: string): Promise<void> {
logger.silly("Setting credentials in native keychain");
const keychain = await this.requireKeychain();
logger.silly("Got native keychain reference");
const MAX_SET_ATTEMPTS = 3;
// Sometimes Keytar has a problem talking to the keychain on the OS. To be more resilient, we retry a few times.
const setPasswordWithRetry = async (service: string, account: string, credentials: string) => {
let attempts = 0;
let error: Error | undefined;
while (attempts < MAX_SET_ATTEMPTS) {
try {
logger.silly("Attempting to set credentials");
await keychain.setPassword(service, account, credentials);
logger.silly("Set credentials successfully");
return;
} catch (error) {
error = error;
logger.warn("Error attempting to set a credentials. Trying again... (" + attempts + ")");
logger.warn(error as any);
attempts++;
await new Promise((resolve) => setTimeout(resolve, 200));
}
}
throw error;
};
if (credentials.length > NativeCredentialsStore.KEYCHAIN_ENTRY_MAX_LENGTH) {
logger.silly("Credentials value is too long. Chunking it.");
let index = 0;
let chunk = 0;
let hasNextChunk = true;
while (hasNextChunk) {
const credentialsChunk = credentials.substring(index, index + NativeCredentialsStore.KEYCHAIN_ENTRY_CHUNK_SIZE);
index += NativeCredentialsStore.KEYCHAIN_ENTRY_CHUNK_SIZE;
hasNextChunk = credentials.length - index > 0;
const content: ChunkedData = {
content: credentialsChunk,
hasNextChunk: hasNextChunk,
};
logger.silly("Setting credentials chunk #" + chunk + " ...");
await setPasswordWithRetry(service, chunk ? `${account}-${chunk}` : account, JSON.stringify(content));
chunk++;
}
} else {
await setPasswordWithRetry(service, account, credentials);
}
}