mirror of
https://github.com/nestriness/nestri.git
synced 2025-12-15 18:25:37 +02:00
Merging this prematurely to make sure the team is on the same boat... like dang! We need to find a better way to do this. Plus it has become too big
207 lines
6.4 KiB
TypeScript
207 lines
6.4 KiB
TypeScript
import { Resource } from "sst"
|
|
import { Select } from "./ui/select";
|
|
import { subjects } from "./subjects"
|
|
import { logger } from "hono/logger";
|
|
import { handle } from "hono/aws-lambda";
|
|
import { PasswordUI } from "./ui/password"
|
|
import { issuer } from "@openauthjs/openauth";
|
|
import { User } from "@nestri/core/user/index"
|
|
import { Email } from "@nestri/core/email/index";
|
|
import { handleDiscord, handleGithub } from "./utils";
|
|
import { GithubAdapter } from "./ui/adapters/github";
|
|
import { DiscordAdapter } from "./ui/adapters/discord";
|
|
import { PasswordAdapter } from "./ui/adapters/password"
|
|
import { type Provider } from "@openauthjs/openauth/provider/provider"
|
|
|
|
type OauthUser = {
|
|
primary: {
|
|
email: any;
|
|
primary: any;
|
|
verified: any;
|
|
};
|
|
avatar: any;
|
|
username: any;
|
|
}
|
|
const app = issuer({
|
|
select: Select({
|
|
providers: {
|
|
device: {
|
|
hide: true,
|
|
},
|
|
},
|
|
}),
|
|
theme: {
|
|
title: "Nestri | Auth",
|
|
primary: "#FF4F01",
|
|
//TODO: Change this in prod
|
|
logo: "https://nestri.io/logo.webp",
|
|
favicon: "https://nestri.io/seo/favicon.ico",
|
|
background: {
|
|
light: "#f5f5f5 ",
|
|
dark: "#171717"
|
|
},
|
|
radius: "lg",
|
|
font: {
|
|
family: "Geist, sans-serif",
|
|
},
|
|
css: `
|
|
@import url('https://fonts.googleapis.com/css2?family=Geist:wght@100;200;300;400;500;600;700;800;900&display=swap');
|
|
`,
|
|
},
|
|
subjects,
|
|
providers: {
|
|
github: GithubAdapter({
|
|
clientID: Resource.GithubClientID.value,
|
|
clientSecret: Resource.GithubClientSecret.value,
|
|
scopes: ["user:email"]
|
|
}),
|
|
discord: DiscordAdapter({
|
|
clientID: Resource.DiscordClientID.value,
|
|
clientSecret: Resource.DiscordClientSecret.value,
|
|
scopes: ["email", "identify"]
|
|
}),
|
|
password: PasswordAdapter(
|
|
PasswordUI({
|
|
sendCode: async (email, code) => {
|
|
console.log("email & code:", email, code)
|
|
// await Email.send(
|
|
// "auth",
|
|
// email,
|
|
// `Nestri code: ${code}`,
|
|
// `Your Nestri login code is ${code}`,
|
|
// )
|
|
},
|
|
}),
|
|
),
|
|
device: {
|
|
type: "device",
|
|
async client(input) {
|
|
if (input.clientSecret !== Resource.AuthFingerprintKey.value) {
|
|
throw new Error("Invalid authorization token");
|
|
}
|
|
const teamSlug = input.params.team;
|
|
if (!teamSlug) {
|
|
throw new Error("Team slug is required");
|
|
}
|
|
|
|
const hostname = input.params.hostname;
|
|
if (!hostname) {
|
|
throw new Error("Hostname is required");
|
|
}
|
|
|
|
return {
|
|
hostname,
|
|
teamSlug
|
|
};
|
|
},
|
|
init() { }
|
|
} as Provider<{ teamSlug: string; hostname: string; }>,
|
|
},
|
|
allow: async (input) => {
|
|
const url = new URL(input.redirectURI);
|
|
const hostname = url.hostname;
|
|
if (hostname.endsWith("nestri.io")) return true;
|
|
if (hostname === "localhost") return true;
|
|
return false;
|
|
},
|
|
success: async (ctx, value) => {
|
|
// if (value.provider === "device") {
|
|
// const team = await Teams.fromSlug(value.teamSlug)
|
|
// console.log("team", team)
|
|
// console.log("teamSlug", value.teamSlug)
|
|
// if (team) {
|
|
// await Instances.create({ hostname: value.hostname, teamID: team.id })
|
|
|
|
// return await ctx.subject("device", {
|
|
// teamSlug: value.teamSlug,
|
|
// hostname: value.hostname,
|
|
// })
|
|
// }
|
|
// }
|
|
|
|
if (value.provider === "password") {
|
|
const email = value.email
|
|
const username = value.username
|
|
const matching = await User.fromEmail(email)
|
|
|
|
//Sign Up
|
|
if (username && !matching) {
|
|
const userID = await User.create({
|
|
name: username,
|
|
email,
|
|
});
|
|
|
|
if (!userID) throw new Error("Error creating user");
|
|
|
|
return ctx.subject("user", {
|
|
userID,
|
|
email
|
|
}, {
|
|
subject: email
|
|
});
|
|
|
|
} else if (matching) {
|
|
//Sign In
|
|
return ctx.subject("user", {
|
|
userID: matching.id,
|
|
email
|
|
}, {
|
|
subject: email
|
|
});
|
|
}
|
|
}
|
|
|
|
let user = undefined as OauthUser | undefined;
|
|
|
|
if (value.provider === "github") {
|
|
const access = value.tokenset.access;
|
|
user = await handleGithub(access)
|
|
}
|
|
|
|
if (value.provider === "discord") {
|
|
const access = value.tokenset.access
|
|
user = await handleDiscord(access)
|
|
}
|
|
|
|
if (user) {
|
|
try {
|
|
const matching = await User.fromEmail(user.primary.email);
|
|
|
|
//Sign Up
|
|
if (!matching) {
|
|
const userID = await User.create({
|
|
email: user.primary.email,
|
|
name: user.username,
|
|
avatarUrl: user.avatar
|
|
});
|
|
|
|
if (!userID) throw new Error("Error creating user");
|
|
|
|
return ctx.subject("user", {
|
|
userID,
|
|
email: user.primary.email
|
|
}, {
|
|
subject: user.primary.email
|
|
});
|
|
} else {
|
|
//Sign In
|
|
return await ctx.subject("user", {
|
|
userID: matching.id,
|
|
email: user.primary.email
|
|
}, {
|
|
subject: user.primary.email
|
|
});
|
|
}
|
|
|
|
} catch (error) {
|
|
console.error("error registering the user", error)
|
|
}
|
|
|
|
}
|
|
|
|
throw new Error("Something went seriously wrong");
|
|
},
|
|
}).use(logger())
|
|
|
|
export const handler = handle(app)
|