async setPassword()

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);
    }
  }