{"version":3,"file":"security.mjs","names":[],"sources":["../src/security.ts"],"sourcesContent":["import { assert } from './utils/assert.js';\nimport { createDebugLogger } from './utils/debug.js';\nconst debug = createDebugLogger('security');\nimport type { Config } from './config.js';\nimport type { ISecurity } from 'soap';\nimport {\n  ClientSSLSecurity,\n  ClientSSLSecurityPFX,\n  BasicAuthSecurity,\n} from 'soap';\nimport fs from 'node:fs';\n\n/**\n * Security configuration using a PFX / PKCS #12 certificate.\n * Used to authenticate with the B2B services using a client certificate.\n */\ninterface PfxSecurity {\n  /**\n   * The content of the PFX / PKCS #12 file.\n   */\n  pfx: Buffer;\n\n  /**\n   * The passphrase for the PFX / PKCS #12 container.\n   */\n  passphrase: string;\n}\n\n/**\n * Security configuration using PEM certificate and key.\n * Used to authenticate with the B2B services using a client certificate.\n */\ninterface PemSecurity {\n  /**\n   * The content of the PEM certificate file.\n   */\n  cert: Buffer;\n\n  /**\n   * The content of the PEM key file.\n   */\n  key: Buffer;\n\n  /**\n   * The passphrase for the PEM key.\n   * Can be omitted if the key is not encrypted.\n   */\n  passphrase?: string;\n}\n\n/**\n * Security configuration using API Gateway credentials.\n * Used to authenticate with the B2B services using an API Key ID and Secret Key.\n * These credentials will be sent as Basic Authentication headers.\n */\ninterface ApiGwSecurity {\n  /**\n   * The API Key ID (used as username for Basic Auth).\n   */\n  apiKeyId: string;\n\n  /**\n   * The API Secret Key (used as password for Basic Auth).\n   */\n  apiSecretKey: string;\n}\n\n/**\n * Supported authentication methods.\n * Used in the `Config` object to specify how the client should authenticate with the B2B services.\n */\nexport type Security = PfxSecurity | PemSecurity | ApiGwSecurity;\n\n/**\n * Asserts that the provided object is a valid {@link Security} configuration.\n * Checks for the presence and validity of required fields for each security type.\n *\n * @param obj - The object to validate.\n * @throws {AssertionError} If the object is not a valid `Security` configuration.\n */\nexport function assertValidSecurity(obj: unknown): asserts obj is Security {\n  assert(!!obj && typeof obj === 'object', 'Must be an object');\n\n  if ('apiKeyId' in obj) {\n    assert(\n      !!obj.apiKeyId &&\n        typeof obj.apiKeyId === 'string' &&\n        obj.apiKeyId.length > 0,\n      'security.apiKeyId must be a string with a length > 0',\n    );\n\n    assert(\n      'apiSecretKey' in obj &&\n        typeof obj.apiSecretKey === 'string' &&\n        obj.apiSecretKey.length > 0,\n      'security.apiSecretKey must be defined when using security.apiKeyId',\n    );\n\n    return;\n  }\n\n  assert(\n    ('pfx' in obj && Buffer.isBuffer(obj.pfx)) ||\n      ('cert' in obj && Buffer.isBuffer(obj.cert)),\n    'security.pfx or security.cert must be buffers',\n  );\n\n  if ('cert' in obj && obj.cert) {\n    assert(\n      'key' in obj && obj.key && Buffer.isBuffer(obj.key),\n      'security.key must be a buffer if security.pem is defined',\n    );\n  }\n}\n\n/**\n * @deprecated Use {@link assertValidSecurity} instead.\n */\nexport function isValidSecurity(obj: unknown): obj is Security {\n  assertValidSecurity(obj);\n  return true;\n}\n\n/**\n * @internal\n */\nexport function prepareSecurity(config: Config): ISecurity {\n  const { security } = config;\n\n  if ('apiKeyId' in security) {\n    const { apiKeyId, apiSecretKey } = security;\n    debug('Using ApiGateway security');\n    return new BasicAuthSecurity(apiKeyId, apiSecretKey);\n  } else if ('pfx' in security) {\n    const { pfx, passphrase } = security;\n    debug('Using PFX certificates');\n    return new ClientSSLSecurityPFX(pfx, passphrase);\n  } else if ('cert' in security) {\n    debug('Using PEM certificates');\n    const { key, cert, passphrase } = security;\n    return new ClientSSLSecurity(\n      key,\n      cert,\n      undefined,\n      passphrase ? { passphrase } : null,\n    );\n  }\n\n  throw new Error('Invalid security object');\n}\n\nlet envSecurity: Security | undefined;\n\n/**\n * Create a security objet from environment variables\n *\n * Will cache data for future use.\n *\n * @returns Security configuration\n */\nexport function fromEnv(): Security {\n  if (envSecurity) {\n    return envSecurity;\n  }\n\n  envSecurity = fromValues(process.env);\n\n  return envSecurity;\n}\n\n/**\n * Convenience function to clear the cached security objet\n */\nexport function clearCache(): void {\n  envSecurity = undefined;\n}\n\n/**\n * Create a security objet from an environment-like object\n *\n * @param env Environment variables\n * @returns Security configuration\n */\nexport function fromValues(env: Record<string, string | undefined>): Security {\n  const { B2B_CERT, B2B_API_KEY_ID, B2B_API_SECRET_KEY } = env;\n\n  if (!B2B_CERT && !B2B_API_KEY_ID) {\n    throw new Error(\n      'Please define a B2B_CERT or a B2B_API_KEY_ID environment variable',\n    );\n  }\n\n  if (B2B_API_KEY_ID) {\n    if (!B2B_API_SECRET_KEY) {\n      throw new Error(\n        `When using B2B_API_KEY_ID, a B2B_API_SECRET_KEY must be defined`,\n      );\n    }\n\n    return {\n      apiKeyId: B2B_API_KEY_ID,\n      apiSecretKey: B2B_API_SECRET_KEY,\n    };\n  }\n\n  if (!B2B_CERT) {\n    throw new Error('Should never happen');\n  }\n\n  if (!fs.existsSync(B2B_CERT)) {\n    throw new Error(`${B2B_CERT} is not a valid certificate file`);\n  }\n\n  const pfxOrPem = fs.readFileSync(B2B_CERT);\n\n  if (!env.B2B_CERT_FORMAT || env.B2B_CERT_FORMAT === 'pfx') {\n    return {\n      pfx: pfxOrPem,\n      passphrase: env.B2B_CERT_PASSPHRASE ?? '',\n    };\n  } else if (env.B2B_CERT_FORMAT === 'pem') {\n    if (!env.B2B_CERT_KEY || !fs.existsSync(env.B2B_CERT_KEY)) {\n      throw new Error(\n        'Please define a valid B2B_CERT_KEY environment variable',\n      );\n    }\n\n    const security: PemSecurity = {\n      cert: pfxOrPem,\n      key: fs.readFileSync(env.B2B_CERT_KEY),\n    };\n\n    if (env.B2B_CERT_PASSPHRASE) {\n      security.passphrase = env.B2B_CERT_PASSPHRASE;\n    }\n\n    return security;\n  }\n\n  throw new Error('Unsupported B2B_CERT_FORMAT, must be pfx or pem');\n}\n"],"mappings":";;;;;AAEA,MAAM,QAAQ,kBAAkB,WAAW;;;;;;;;AA8E3C,SAAgB,oBAAoB,KAAuC;AACzE,QAAO,CAAC,CAAC,OAAO,OAAO,QAAQ,UAAU,oBAAoB;AAE7D,KAAI,cAAc,KAAK;AACrB,SACE,CAAC,CAAC,IAAI,YACJ,OAAO,IAAI,aAAa,YACxB,IAAI,SAAS,SAAS,GACxB,uDACD;AAED,SACE,kBAAkB,OAChB,OAAO,IAAI,iBAAiB,YAC5B,IAAI,aAAa,SAAS,GAC5B,qEACD;AAED;;AAGF,QACG,SAAS,OAAO,OAAO,SAAS,IAAI,IAAI,IACtC,UAAU,OAAO,OAAO,SAAS,IAAI,KAAK,EAC7C,gDACD;AAED,KAAI,UAAU,OAAO,IAAI,KACvB,QACE,SAAS,OAAO,IAAI,OAAO,OAAO,SAAS,IAAI,IAAI,EACnD,2DACD;;;;;AAOL,SAAgB,gBAAgB,KAA+B;AAC7D,qBAAoB,IAAI;AACxB,QAAO;;;;;AAMT,SAAgB,gBAAgB,QAA2B;CACzD,MAAM,EAAE,aAAa;AAErB,KAAI,cAAc,UAAU;EAC1B,MAAM,EAAE,UAAU,iBAAiB;AACnC,QAAM,4BAA4B;AAClC,SAAO,IAAI,kBAAkB,UAAU,aAAa;YAC3C,SAAS,UAAU;EAC5B,MAAM,EAAE,KAAK,eAAe;AAC5B,QAAM,yBAAyB;AAC/B,SAAO,IAAI,qBAAqB,KAAK,WAAW;YACvC,UAAU,UAAU;AAC7B,QAAM,yBAAyB;EAC/B,MAAM,EAAE,KAAK,MAAM,eAAe;AAClC,SAAO,IAAI,kBACT,KACA,MACA,KAAA,GACA,aAAa,EAAE,YAAY,GAAG,KAC/B;;AAGH,OAAM,IAAI,MAAM,0BAA0B;;AAG5C,IAAI;;;;;;;;AASJ,SAAgB,UAAoB;AAClC,KAAI,YACF,QAAO;AAGT,eAAc,WAAW,QAAQ,IAAI;AAErC,QAAO;;;;;AAMT,SAAgB,aAAmB;AACjC,eAAc,KAAA;;;;;;;;AAShB,SAAgB,WAAW,KAAmD;CAC5E,MAAM,EAAE,UAAU,gBAAgB,uBAAuB;AAEzD,KAAI,CAAC,YAAY,CAAC,eAChB,OAAM,IAAI,MACR,oEACD;AAGH,KAAI,gBAAgB;AAClB,MAAI,CAAC,mBACH,OAAM,IAAI,MACR,kEACD;AAGH,SAAO;GACL,UAAU;GACV,cAAc;GACf;;AAGH,KAAI,CAAC,SACH,OAAM,IAAI,MAAM,sBAAsB;AAGxC,KAAI,CAAC,GAAG,WAAW,SAAS,CAC1B,OAAM,IAAI,MAAM,GAAG,SAAS,kCAAkC;CAGhE,MAAM,WAAW,GAAG,aAAa,SAAS;AAE1C,KAAI,CAAC,IAAI,mBAAmB,IAAI,oBAAoB,MAClD,QAAO;EACL,KAAK;EACL,YAAY,IAAI,uBAAuB;EACxC;UACQ,IAAI,oBAAoB,OAAO;AACxC,MAAI,CAAC,IAAI,gBAAgB,CAAC,GAAG,WAAW,IAAI,aAAa,CACvD,OAAM,IAAI,MACR,0DACD;EAGH,MAAM,WAAwB;GAC5B,MAAM;GACN,KAAK,GAAG,aAAa,IAAI,aAAa;GACvC;AAED,MAAI,IAAI,oBACN,UAAS,aAAa,IAAI;AAG5B,SAAO;;AAGT,OAAM,IAAI,MAAM,kDAAkD"}