| 1 | import { assert, it } from "@effect/vitest"; |
| 2 | import * as Effect from "effect/Effect"; |
| 3 | import * as Layer from "effect/Layer"; |
| 4 | import * as Redacted from "effect/Redacted"; |
| 5 | import * as HttpClient from "effect/http/HttpClient"; |
| 6 | import * as HttpClientResponse from "effect/http/HttpClientResponse"; |
| 7 | import { describe } from "vite-plus/test"; |
| 8 | |
| 9 | import * as OpenCode2Client from "./OpenCode2Client.ts"; |
| 10 | |
| 11 | const INFO_BODY = '{"version":"2.0.18","pid":4242,"urls":[],"paths":{"tmp":"/tmp"}}'; |
| 12 | |
| 13 | /** Sends one request through the client and returns the Authorization header it carried. */ |
| 14 | const authorizationFor = (password: string | Redacted.Redacted) => { |
| 15 | const seen: Array<string | undefined> = []; |
| 16 | const layerCapturing = Layer.succeed( |
| 17 | HttpClient.HttpClient, |
| 18 | HttpClient.make((request) => |
| 19 | Effect.sync(() => { |
| 20 | seen.push(request.headers.authorization); |
| 21 | return HttpClientResponse.fromWeb( |
| 22 | request, |
| 23 | new Response(INFO_BODY, { headers: { "content-type": "application/json" } }), |
| 24 | ); |
| 25 | }), |
| 26 | ), |
| 27 | ); |
| 28 | return Effect.gen(function* () { |
| 29 | const opencode = yield* OpenCode2Client.OpenCode2Client; |
| 30 | const { client } = yield* opencode.connect({ baseUrl: "http://127.0.0.1:4096", password }); |
| 31 | yield* client.server.info(); |
| 32 | return seen[0]; |
| 33 | }).pipe(Effect.provide(OpenCode2Client.layer.pipe(Layer.provide(layerCapturing)))); |
| 34 | }; |
| 35 | |
| 36 | const utf8Basic = (password: string) => |
| 37 | `Basic ${Buffer.from(`opencode:${password}`, "utf8").toString("base64")}`; |
| 38 | |
| 39 | describe("OpenCode2Client authorization", () => { |
| 40 | // OpenCode decodes Basic credentials as UTF-8. Latin-1 (`btoa`) encoding gets |
| 41 | // `pässwörd` rejected with a 401 and throws on characters such as `€`. |
| 42 | it.effect("encodes non-ASCII passwords as UTF-8", () => |
| 43 | Effect.gen(function* () { |
| 44 | assert.strictEqual(yield* authorizationFor("pässwörd"), utf8Basic("pässwörd")); |
| 45 | assert.strictEqual(yield* authorizationFor("pass€word"), utf8Basic("pass€word")); |
| 46 | assert.strictEqual(yield* authorizationFor(Redacted.make("pässwörd")), utf8Basic("pässwörd")); |
| 47 | }), |
| 48 | ); |
| 49 | }); |