Skip to content

Commit

Permalink
chore: initial oauth work for email providers
Browse files Browse the repository at this point in the history
  • Loading branch information
potts99 committed Oct 20, 2024
1 parent c531c08 commit b4064cd
Show file tree
Hide file tree
Showing 7 changed files with 388 additions and 30 deletions.
2 changes: 2 additions & 0 deletions apps/api/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@
"typescript": "^5.3.2"
},
"dependencies": {
"@azure/identity": "^4.5.0",
"@fastify/cookie": "^9.0.4",
"@fastify/cors": "^8.3.0",
"@fastify/multipart": "^8.2.0",
Expand All @@ -42,6 +43,7 @@
"fastify-formidable": "^3.0.2",
"fastify-multer": "^2.0.3",
"formidable": "^3.5.1",
"google-auth-library": "^9.14.2",
"got": "^13.0.0",
"handlebars": "^4.7.8",
"i": "^0.3.7",
Expand Down
13 changes: 6 additions & 7 deletions apps/api/src/controllers/config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -305,17 +305,16 @@ export function configRoutes(fastify: FastifyInstance) {
});
}

const emails = await prisma.email.findMany();
const email = emails[0];
const email = await prisma.email.findFirst();

const mail = nodeMailer.createTransport({
// @ts-ignore
host: email.host,
port: email.port,
secure: email.port === "465" ? true : false,
host: email?.host,
port: email?.port,
secure: email?.port === "465" ? true : false,
auth: {
user: email.user,
pass: email.pass,
user: email?.user,
pass: email?.pass,
},
});

Expand Down
1 change: 0 additions & 1 deletion apps/api/src/lib/nodemailer/ticket/assigned.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,6 @@ export async function sendAssignedEmail(email: any) {

if (emails.length > 0) {
if (process.env.ENVIRONMENT === "development") {
// let testAccount = await nodeMailer.createTestAccount();
mail = nodeMailer.createTransport({
host: "localhost",
port: 1025,
Expand Down
72 changes: 72 additions & 0 deletions apps/api/src/lib/nodemailer/transport.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
import { prisma } from "../../prisma";

const nodemailer = require("nodemailer");
const { google } = require("google-auth-library");
const { ConfidentialClientApplication } = require("@azure/identity");

// Environment variables or configuration
const CLIENT_ID = process.env.CLIENT_ID;
const CLIENT_SECRET = process.env.CLIENT_SECRET;
const REFRESH_TOKEN = process.env.REFRESH_TOKEN;
const TENANT_ID = process.env.TENANT_ID;

export async function createTransportProvider() {
const provider = await prisma.email.findFirst({});

if (CLIENT_ID && CLIENT_SECRET && (REFRESH_TOKEN || TENANT_ID)) {
// OAuth2 configuration
if (EMAIL_SERVICE === "gmail") {
// Gmail
const oAuth2Client = new google.auth.OAuth2(CLIENT_ID, CLIENT_SECRET);
oAuth2Client.setCredentials({ refresh_token: REFRESH_TOKEN });
const accessToken = await oAuth2Client.getAccessToken();

return nodemailer.createTransport({
service: "gmail",
auth: {
type: "OAuth2",
user: EMAIL_USER,
clientId: CLIENT_ID,
clientSecret: CLIENT_SECRET,
refreshToken: REFRESH_TOKEN,
accessToken: accessToken.token,
},
});
} else if (EMAIL_SERVICE === "microsoft") {
// Microsoft
const cca = new ConfidentialClientApplication({
auth: {
clientId: CLIENT_ID,
authority: `https://login.microsoftonline.com/${TENANT_ID}`,
clientSecret: CLIENT_SECRET,
},
});

const result = await cca.acquireTokenByClientCredential({
scopes: ["https://graph.microsoft.com/.default"],
});

return nodemailer.createTransport({
service: "hotmail",
auth: {
type: "OAuth2",
user: EMAIL_USER,
clientId: CLIENT_ID,
clientSecret: CLIENT_SECRET,
accessToken: result.accessToken,
},
});
}
} else if (EMAIL_USER && EMAIL_PASS) {
// Username/password configuration
return nodemailer.createTransport({
service: EMAIL_SERVICE,
auth: {
user: EMAIL_USER,
pass: EMAIL_PASS,
},
});
} else {
throw new Error("No valid authentication method configured.");
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
-- AlterTable
ALTER TABLE "Email" ADD COLUMN "clientId" TEXT,
ADD COLUMN "clientSecret" TEXT,
ADD COLUMN "refreshToken" TEXT,
ADD COLUMN "serviceType" TEXT NOT NULL DEFAULT 'other',
ADD COLUMN "tenantId" TEXT,
ALTER COLUMN "pass" DROP NOT NULL;
33 changes: 19 additions & 14 deletions apps/api/src/prisma/schema.prisma
Original file line number Diff line number Diff line change
Expand Up @@ -37,10 +37,10 @@ model SAMLProvider {
}

model openIdConfig {
id Int @id @default(autoincrement())
clientId String
issuer String
redirectUri String
id Int @id @default(autoincrement())
clientId String
issuer String
redirectUri String
}

model Session {
Expand Down Expand Up @@ -260,16 +260,21 @@ model Slack {
}

model Email {
id String @id @default(uuid())
createdAt DateTime @default(now())
updatedAt DateTime @default(now())
active Boolean @default(false)
user String
pass String
secure Boolean @default(false)
host String
reply String
port String
id String @id @default(uuid())
createdAt DateTime @default(now())
updatedAt DateTime @default(now())
active Boolean @default(false)
user String
pass String?
secure Boolean @default(false)
host String
reply String
port String
serviceType String @default("other")
clientId String?
clientSecret String?
tenantId String?
refreshToken String?
}

model Config {
Expand Down
Loading

0 comments on commit b4064cd

Please sign in to comment.