| 1 | import * as Crypto from "effect/Crypto"; |
| 2 | import * as Effect from "effect/Effect"; |
| 3 | import * as Hex from "effect/encoding/Hex"; |
| 4 | import * as ServerSecretStore from "../auth/ServerSecretStore.ts"; |
| 5 | |
| 6 | /** A provider binding stores opaque bytes; only its adapter decodes or refreshes them. */ |
| 7 | export const make = Effect.fn("ProviderCredentialStore.make")(function* ( |
| 8 | driver: string, |
| 9 | bindingId: string, |
| 10 | ) { |
| 11 | const secrets = yield* ServerSecretStore.ServerSecretStore; |
| 12 | const crypto = yield* Crypto.Crypto; |
| 13 | // Hash the tuple so arbitrary bindings cannot escape or exceed a filename. |
| 14 | const bindingHash = yield* crypto |
| 15 | .digest("SHA-256", new TextEncoder().encode(`${driver.length}:${driver}${bindingId}`)) |
| 16 | .pipe(Effect.map(Hex.encode), Effect.orDie); |
| 17 | const key = `provider-auth-${bindingHash}`; |
| 18 | return { |
| 19 | binding: { owner: "t3" as const, key }, |
| 20 | get: secrets.get(key), |
| 21 | set: (credentials: Uint8Array) => secrets.set(key, credentials), |
| 22 | remove: secrets.remove(key), |
| 23 | }; |
| 24 | }); |