Merge pull request 'account-claim' (#98) from account-claim into main
All checks were successful
Continuous Integration / Update Development (push) Successful in 2m35s
Continuous Deployment / Update Deployment (push) Successful in 2m39s

Reviewed-on: #98
This commit was merged in pull request #98.
This commit is contained in:
2025-12-14 21:52:22 -06:00
3 changed files with 43 additions and 24 deletions

View File

@@ -10,10 +10,14 @@ import { Role } from '@app/shared/types/roles';
import pool from '../db'; import pool from '../db';
import { requireLogin } from '../middleware/auth'; import { requireLogin } from '../middleware/auth';
import { getUserRoles } from '../services/rolesService'; import { getUserRoles } from '../services/rolesService';
import { getUserState } from '../services/memberService'; import { getUserState, mapDiscordtoID } from '../services/memberService';
import { MemberState } from '@app/shared/types/member'; import { MemberState } from '@app/shared/types/member';
import { toDateTime } from '@app/shared/utils/time';
const querystring = require('querystring'); const querystring = require('querystring');
function parseJwt(token) {
return JSON.parse(Buffer.from(token.split('.')[1], 'base64').toString());
}
passport.use(new OpenIDConnectStrategy({ passport.use(new OpenIDConnectStrategy({
issuer: process.env.AUTH_ISSUER, issuer: process.env.AUTH_ISSUER,
@@ -23,16 +27,17 @@ passport.use(new OpenIDConnectStrategy({
clientID: process.env.AUTH_CLIENT_ID, clientID: process.env.AUTH_CLIENT_ID,
clientSecret: process.env.AUTH_CLIENT_SECRET, clientSecret: process.env.AUTH_CLIENT_SECRET,
callbackURL: process.env.AUTH_REDIRECT_URI, callbackURL: process.env.AUTH_REDIRECT_URI,
scope: ['openid', 'profile'] scope: ['openid', 'profile', 'discord']
}, async function verify(issuer, sub, profile, jwtClaims, accessToken, refreshToken, params, cb) { }, async function verify(issuer, sub, profile, jwtClaims, accessToken, refreshToken, params, cb) {
// console.log('--- OIDC verify() called ---'); // console.log('--- OIDC verify() called ---');
// console.log('issuer:', issuer); // console.log('issuer:', issuer);
// console.log('sub:', sub); // console.log('sub:', sub);
// // console.log('profile:', JSON.stringify(profile, null, 2)); // // console.log('discord:', discord);
// console.log('profile:', profile); // console.log('profile:', profile);
// console.log('id_token claims:', JSON.stringify(jwtClaims, null, 2)); // console.log('jwt: ', parseJwt(jwtClaims));
// console.log('preferred_username:', jwtClaims?.preferred_username); // console.log('params:', params);
try { try {
var con = await pool.getConnection(); var con = await pool.getConnection();
@@ -41,20 +46,37 @@ passport.use(new OpenIDConnectStrategy({
//lookup existing user //lookup existing user
const existing = await con.query(`SELECT id FROM members WHERE authentik_issuer = ? AND authentik_sub = ? LIMIT 1;`, [issuer, sub]); const existing = await con.query(`SELECT id FROM members WHERE authentik_issuer = ? AND authentik_sub = ? LIMIT 1;`, [issuer, sub]);
let memberId; let memberId: number;
//if member exists //if member exists
if (existing.length > 0) { if (existing.length > 0) {
memberId = existing[0].id; memberId = existing[0].id;
} else { } else {
//otherwise: create account //otherwise: create account
const username = sub.username; const jwt = parseJwt(jwtClaims);
const discordID = jwt.discord.id as number;
const result = await con.query( //check if account is available to claim
`INSERT INTO members (name, authentik_sub, authentik_issuer) VALUES (?, ?, ?)`, memberId = await mapDiscordtoID(discordID);
[username, sub, issuer]
) if (memberId === null) {
memberId = Number(result.insertId); // create new account
const username = sub.username;
const result = await con.query(
`INSERT INTO members (name, authentik_sub, authentik_issuer) VALUES (?, ?, ?)`,
[username, sub, issuer]
)
memberId = Number(result.insertId);
} else {
// claim existing account
const result = await con.query(
`UPDATE members SET authentik_sub = ?, authentik_issuer = ? WHERE id = ?;`,
[sub, issuer, memberId]
)
}
} }
await con.query(`UPDATE members SET last_login = ? WHERE id = ?`, [toDateTime(new Date()), memberId])
await con.commit(); await con.commit();
return cb(null, { memberId }); return cb(null, { memberId });
} catch (error) { } catch (error) {
@@ -116,11 +138,10 @@ passport.deserializeUser(function (user, cb) {
var userData: { id: number, name: string, roles: Role[], state: MemberState }; var userData: { id: number, name: string, roles: Role[], state: MemberState };
try { try {
var con = await pool.getConnection(); var con = await pool.getConnection();
let userResults = await con.query(`SELECT id, name FROM members WHERE id = ?;`, [memberID]) let userResults = await con.query(`SELECT id, name FROM members WHERE id = ?;`, [memberID])
userData = userResults[0]; userData = userResults[0];
let userRoles = await getUserRoles(memberID); let userRoles = await getUserRoles(memberID);
userData.roles = userRoles; userData.roles = userRoles || [];
userData.state = await getUserState(memberID); userData.state = await getUserState(memberID);
} catch (error) { } catch (error) {
console.error(error) console.error(error)

View File

@@ -38,18 +38,11 @@ router.get('/me', [requireLogin], async (req, res) => {
try { try {
const { id, name, state } = await getUserData(req.user.id); const { id, name, state } = await getUserData(req.user.id);
// const LOAData = await pool.query(
// `SELECT *
// FROM leave_of_absences
// WHERE member_id = ?
// AND deleted = 0
// AND UTC_TIMESTAMP() BETWEEN start_date AND end_date;`, req.user.id);
const LOAData = await getUserActiveLOA(req.user.id); const LOAData = await getUserActiveLOA(req.user.id);
const roleData = await getUserRoles(req.user.id); const roleData = await getUserRoles(req.user.id);
const userDataFull = { id, name, state, LOAData, roleData }; const userDataFull = { id, name, state, LOAData, roleData };
console.log(userDataFull)
res.status(200).json(userDataFull); res.status(200).json(userDataFull);
} catch (error) { } catch (error) {
console.error('Error fetching user data:', error); console.error('Error fetching user data:', error);

View File

@@ -15,9 +15,8 @@ export async function setUserState(userID: number, state: MemberState) {
} }
export async function getUserState(user: number): Promise<MemberState> { export async function getUserState(user: number): Promise<MemberState> {
let out = await pool.query(`SELECT state FROM members WHERE id = ?`, [user]); let out = await pool.query(`SELECT state FROM members WHERE id = ?`, [user]);
console.log('hi') return (out[0].state as MemberState);
return (out[0].state as MemberState);
} }
export async function getMemberSettings(id: number): Promise<memberSettings> { export async function getMemberSettings(id: number): Promise<memberSettings> {
@@ -54,4 +53,10 @@ export async function getMembersFull(ids: number[]): Promise<Member[]> {
const sql = `SELECT * FROM view_member_rank_unit_status_latest WHERE member_id IN (?);`; const sql = `SELECT * FROM view_member_rank_unit_status_latest WHERE member_id IN (?);`;
const res: Member[] = await pool.query(sql, [ids]); const res: Member[] = await pool.query(sql, [ids]);
return res; return res;
}
export async function mapDiscordtoID(id: number): Promise<number | null> {
const sql = `SELECT id FROM members WHERE discord_id = ?;`
let res = await pool.query(sql, [id]);
return res.length > 0 ? res[0].id : null;
} }