shellphone.app/app/features/phone-calls/loaders/twilio-token.ts

74 lines
2.3 KiB
TypeScript
Raw Normal View History

2022-05-24 21:13:08 +00:00
import { type LoaderFunction } from "@remix-run/node";
import Twilio from "twilio";
import { refreshSessionData, requireLoggedIn } from "~/utils/auth.server";
2022-06-11 17:29:58 +00:00
import { decrypt, encrypt } from "~/utils/encryption";
2022-05-24 21:13:08 +00:00
import db from "~/utils/db.server";
import { commitSession } from "~/utils/session.server";
import getTwilioClient from "~/utils/twilio.server";
import logger from "~/utils/logger.server";
2022-05-24 21:13:08 +00:00
export type TwilioTokenLoaderData = string;
const loader: LoaderFunction = async ({ request }) => {
2022-06-11 17:29:58 +00:00
const { user, twilio } = await requireLoggedIn(request);
if (!twilio) {
logger.warn("Twilio account is not connected");
return null;
}
const twilioAccount = await db.twilioAccount.findUnique({ where: { accountSid: twilio.accountSid } });
2022-05-24 21:13:08 +00:00
if (!twilioAccount || !twilioAccount.twimlAppSid) {
logger.warn(
"Twilio account is connected but the background jobs didn't run properly, this shouldn't be happening",
);
return null;
2022-05-24 21:13:08 +00:00
}
const twilioClient = getTwilioClient(twilioAccount);
let shouldRefreshSession = false;
let { apiKeySid, apiKeySecret } = twilioAccount;
if (apiKeySid && apiKeySecret) {
try {
await twilioClient.keys.get(apiKeySid).fetch();
} catch (error: any) {
if (error.code !== 20404) {
throw error;
}
apiKeySid = null;
apiKeySecret = null;
}
}
if (!apiKeySid || !apiKeySecret) {
shouldRefreshSession = true;
const apiKey = await twilioClient.newKeys.create({ friendlyName: "Shellphone" });
apiKeySid = apiKey.sid;
2022-06-11 17:29:58 +00:00
apiKeySecret = encrypt(apiKey.secret);
2022-05-24 21:13:08 +00:00
await db.twilioAccount.update({
where: { accountSid: twilioAccount.accountSid },
2022-06-11 17:29:58 +00:00
data: { apiKeySid, apiKeySecret },
2022-05-24 21:13:08 +00:00
});
}
2022-06-11 17:29:58 +00:00
const accessToken = new Twilio.jwt.AccessToken(twilioAccount.accountSid, apiKeySid, decrypt(apiKeySecret), {
identity: `${twilio.accountSid}__${user.id}`,
2022-05-24 21:13:08 +00:00
ttl: 3600,
});
const grant = new Twilio.jwt.AccessToken.VoiceGrant({
outgoingApplicationSid: twilioAccount.twimlAppSid,
incomingAllow: true,
});
accessToken.addGrant(grant);
const headers = new Headers({ "Content-Type": "text/plain" });
if (shouldRefreshSession) {
const { session } = await refreshSessionData(request);
headers.set("Set-Cookie", await commitSession(session));
}
return new Response(accessToken.toJwt(), { headers });
};
export default loader;