| ... | ... | @@ -3,6 +3,7 @@ import * as Schema from "effect/Schema"; |
| 3 | 3 | const PAIRING_TOKEN_PARAM = "token"; |
| 4 | 4 | const HOSTED_PAIRING_HOST_PARAM = "host"; |
| 5 | 5 | const HOSTED_PAIRING_LABEL_PARAM = "label"; |
| 6 | const SUPPORTED_REMOTE_BACKEND_PROTOCOLS = new Set(["http:", "https:", "ws:", "wss:"]); |
| 6 | 7 | |
| 7 | 8 | const readHashParams = (url: URL): URLSearchParams => |
| 8 | 9 | new URLSearchParams(url.hash.startsWith("#") ? url.hash.slice(1) : url.hash); |
| ... | ... | @@ -18,7 +19,10 @@ export class RemoteBackendUrlMissingError extends Schema.TaggedErrorClass<Remote |
| 18 | 19 | |
| 19 | 20 | export class RemotePairingUrlInvalidError extends Schema.TaggedErrorClass<RemotePairingUrlInvalidError>()( |
| 20 | 21 | "RemotePairingUrlInvalidError", |
| 21 | | { cause: Schema.Defect() }, |
| 22 | { |
| 23 | cause: Schema.optional(Schema.Defect()), |
| 24 | protocol: Schema.optional(Schema.String), |
| 25 | }, |
| 22 | 26 | ) { |
| 23 | 27 | override get message(): string { |
| 24 | 28 | return "Pairing URL is invalid."; |
| ... | ... | @@ -29,7 +33,8 @@ export class RemoteBackendUrlInvalidError extends Schema.TaggedErrorClass<Remote |
| 29 | 33 | "RemoteBackendUrlInvalidError", |
| 30 | 34 | { |
| 31 | 35 | source: Schema.Literals(["direct-host", "hosted-pairing-host"]), |
| 32 | | cause: Schema.Defect(), |
| 36 | cause: Schema.optional(Schema.Defect()), |
| 37 | protocol: Schema.optional(Schema.String), |
| 33 | 38 | }, |
| 34 | 39 | ) { |
| 35 | 40 | override get message(): string { |
| ... | ... | @@ -64,6 +69,9 @@ export const RemotePairingTargetError = Schema.Union([ |
| 64 | 69 | ]); |
| 65 | 70 | export type RemotePairingTargetError = typeof RemotePairingTargetError.Type; |
| 66 | 71 | |
| 72 | const hasSupportedRemoteBackendProtocol = (url: URL): boolean => |
| 73 | SUPPORTED_REMOTE_BACKEND_PROTOCOLS.has(url.protocol); |
| 74 | |
| 67 | 75 | const normalizeRemoteBaseUrl = ( |
| 68 | 76 | rawValue: string, |
| 69 | 77 | source: RemoteBackendUrlInvalidError["source"], |
| ... | ... | @@ -83,6 +91,12 @@ const normalizeRemoteBaseUrl = ( |
| 83 | 91 | } catch (cause) { |
| 84 | 92 | throw new RemoteBackendUrlInvalidError({ source, cause }); |
| 85 | 93 | } |
| 94 | if (!hasSupportedRemoteBackendProtocol(url)) { |
| 95 | throw new RemoteBackendUrlInvalidError({ |
| 96 | source, |
| 97 | protocol: url.protocol, |
| 98 | }); |
| 99 | } |
| 86 | 100 | url.pathname = "/"; |
| 87 | 101 | url.search = ""; |
| 88 | 102 | url.hash = ""; |
| ... | ... | @@ -184,6 +198,11 @@ export const resolveRemotePairingTarget = (input: { |
| 184 | 198 | } catch (cause) { |
| 185 | 199 | throw new RemotePairingUrlInvalidError({ cause }); |
| 186 | 200 | } |
| 201 | if (!hasSupportedRemoteBackendProtocol(url)) { |
| 202 | throw new RemotePairingUrlInvalidError({ |
| 203 | protocol: url.protocol, |
| 204 | }); |
| 205 | } |
| 187 | 206 | const hostedPairingRequest = readHostedPairingRequest(url); |
| 188 | 207 | if (hostedPairingRequest) { |
| 189 | 208 | const hostedBackendUrl = normalizeRemoteBaseUrl( |