ekyc_send_sms_challenge.ts (1793B)
1 import { PhoneSmsChallengeSender } from "../../core/application/phone/register.ts"; 2 import * as V from "$valita"; 3 4 export type SwisscomOptions = { 5 SWISSCOM_SMS_TOKEN_ENDPOINT: string; 6 SWISSCOM_SMS_MESSAGE_ENDPOINT: string; 7 SWISSCOM_SMS_CLIENT_ID: string; 8 SWISSCOM_SMS_CLIENT_SECRET: string; 9 }; 10 11 export class SwisscomPhoneSmsChallengeSenderAdapter 12 implements PhoneSmsChallengeSender { 13 constructor(private readonly options: SwisscomOptions) { 14 } 15 16 async send(phoneNumber: string, code: string): Promise<void> { 17 const accessToken = await this.connect(); 18 const response = await fetch( 19 `${this.options.SWISSCOM_SMS_MESSAGE_ENDPOINT}`, 20 { 21 method: "POST", 22 headers: { 23 "Authorization": `Bearer ${accessToken}`, 24 "Content-Type": "application/json", 25 "SCS-Version": "2", 26 }, 27 body: JSON.stringify({ 28 to: phoneNumber, 29 text: `To verify your phone number, enter the code: ${code}`, 30 }), 31 }, 32 ); 33 if (response.status !== 201) { 34 const json = await response.json(); 35 throw new Error(JSON.stringify(json)); 36 } 37 } 38 39 async connect(): Promise<unknown> { 40 const response = await fetch( 41 `${this.options.SWISSCOM_SMS_TOKEN_ENDPOINT}?grant_type=client_credentials`, 42 { 43 method: "POST", 44 headers: { 45 "Content-Type": "application/x-www-form-urlencoded", 46 "Content-Length": "0", 47 "Authorization": "Basic " + 48 btoa( 49 `${this.options.SWISSCOM_SMS_CLIENT_ID}:${this.options.SWISSCOM_SMS_CLIENT_SECRET}`, 50 ), 51 }, 52 }, 53 ); 54 const json = await response.json(); 55 return V.object({ access_token: V.string() }) 56 .parse(json, { mode: "strip" }) 57 .access_token; 58 } 59 }