diff --git a/server/package.json b/server/package.json index 16ea7dc..3dac323 100644 --- a/server/package.json +++ b/server/package.json @@ -50,6 +50,9 @@ "@types/express-session": "^1.17.10", "@types/jsonwebtoken": "^9.0.5", "@types/passport": "^1.0.16", + "@types/passport-github2": "^1.2.9", + "@types/passport-jwt": "^4.0.1", + "@types/passport-local": "^1.0.38", "@types/passport-oauth2": "^1.4.15", "@types/validator": "^13.11.9", "concurrently": "^8.2.2", diff --git a/server/src/auth/githubStrategy.js b/server/src/auth/githubStrategy.ts similarity index 66% rename from server/src/auth/githubStrategy.js rename to server/src/auth/githubStrategy.ts index e6fe4ce..a20fdc6 100644 --- a/server/src/auth/githubStrategy.js +++ b/server/src/auth/githubStrategy.ts @@ -1,9 +1,16 @@ -import GitHubStrategy from 'passport-github2' +import { Strategy as GitHubStrategy } from 'passport-github2' +import type { Profile } from 'passport' +import type { VerifyCallback } from 'passport-oauth2' import config from '../config.js' import oauthVerify from './oauthVerify.js' -function verify(accessToken, refreshToken, profile, cb) { +function verify( + accessToken: string, + refreshToken: string, + profile: Profile, + cb: VerifyCallback +) { oauthVerify('github', profile, { 'socialLogins.github.id': profile.id }, cb) } diff --git a/server/src/auth/googleStrategy.js b/server/src/auth/googleStrategy.ts similarity index 79% rename from server/src/auth/googleStrategy.js rename to server/src/auth/googleStrategy.ts index a29b79d..b02912a 100644 --- a/server/src/auth/googleStrategy.js +++ b/server/src/auth/googleStrategy.ts @@ -1,9 +1,9 @@ -import GoogleStrategy from 'passport-google-oidc' +import { Strategy as GoogleStrategy } from 'passport-google-oidc' import config from '../config.js' import oauthVerify from './oauthVerify.js' -function verify(issuer, profile, cb) { +function verify(issuer: string, profile: any, cb: any) { oauthVerify('google', profile, { 'socialLogins.google.id': profile.id }, cb) } @@ -15,7 +15,6 @@ export default enabled clientID: config.google.clientID, clientSecret: config.google.clientSecret, callbackURL: `${config.baseUrl}/api/v1/auth/google/callback`, - scope: ['profile', 'email'], }, verify ) diff --git a/server/src/auth/jwtStrategy.js b/server/src/auth/jwtStrategy.ts similarity index 73% rename from server/src/auth/jwtStrategy.js rename to server/src/auth/jwtStrategy.ts index 446b852..b83f8e1 100644 --- a/server/src/auth/jwtStrategy.js +++ b/server/src/auth/jwtStrategy.ts @@ -1,4 +1,5 @@ import { Strategy as JwtStrategy, ExtractJwt } from 'passport-jwt' +import type { VerifyCallback } from 'passport-jwt' import config from '../config.js' const jwtOptions = { @@ -6,7 +7,7 @@ const jwtOptions = { secretOrKey: config.secret, } -function verifyJwt(jwtPayload, done) { +function verifyJwt(jwtPayload: any, done: VerifyCallback) { return done(null, jwtPayload) } diff --git a/server/src/auth/passport.js b/server/src/auth/passport.ts similarity index 59% rename from server/src/auth/passport.js rename to server/src/auth/passport.ts index c884d5a..bb13161 100644 --- a/server/src/auth/passport.js +++ b/server/src/auth/passport.ts @@ -1,11 +1,18 @@ import passport from 'passport' import { UserProfile } from '@linux-odyssey/models' +import type { Express } from 'express' import passwordStrategy from './passwordStrategy.js' import jwtStrategy from './jwtStrategy.js' import googleStrategy from './googleStrategy.js' import githubStrategy from './githubStrategy.js' import logger from '../utils/logger.js' +interface SerializedUser extends Express.User { + _id: string + username: string + email: string +} + passport.use(passwordStrategy) passport.use(jwtStrategy) @@ -17,32 +24,29 @@ const enabledMethods = { logger.info('Enabled login methods', enabledMethods) -if (enabledMethods.google) { +if (googleStrategy !== null) { passport.use(googleStrategy) } -if (enabledMethods.github) { +if (githubStrategy !== null) { passport.use(githubStrategy) } -passport.serializeUser((user, done) => { +passport.serializeUser((user: Express.User, done: any) => { process.nextTick(async () => { try { - if (user._id && !(await UserProfile.exists({ user: user._id }))) { - await UserProfile.create({ user: user._id }) + const serializedUser = user as SerializedUser + if (!(await UserProfile.exists({ user: serializedUser._id }))) { + await UserProfile.create({ user: serializedUser._id }) } - done(null, { - _id: user._id, - username: user.username, - email: user.email, - }) + done(null, serializedUser) } catch (err) { done(err) } }) }) -passport.deserializeUser((user, done) => { +passport.deserializeUser((user: SerializedUser, done) => { process.nextTick(() => { done(null, user) }) diff --git a/server/src/auth/passwordStrategy.js b/server/src/auth/passwordStrategy.ts similarity index 52% rename from server/src/auth/passwordStrategy.js rename to server/src/auth/passwordStrategy.ts index 6334178..d280cd8 100644 --- a/server/src/auth/passwordStrategy.js +++ b/server/src/auth/passwordStrategy.ts @@ -1,8 +1,19 @@ +/* eslint-disable no-unused-vars */ import bcrypt from 'bcrypt' -import LocalStrategy from 'passport-local' +import { Strategy as LocalStrategy } from 'passport-local' +import type { IVerifyOptions } from 'passport-local' +import type { Express } from 'express' import { User } from '@linux-odyssey/models' -async function verifyPassword(username, password, done) { +async function verifyPassword( + username: string, + password: string, + done: ( + error: any, + user?: Express.User | false, + options?: IVerifyOptions + ) => void +) { try { const user = await User.findOne({ $or: [{ username }, { email: username }], @@ -11,7 +22,10 @@ async function verifyPassword(username, password, done) { return done(null, false, { message: 'Incorrect username or password.' }) } - const isPasswordValid = await bcrypt.compare(password, user.hashedPassword) + const isPasswordValid = await bcrypt.compare( + password, + user.hashedPassword || '' + ) if (!isPasswordValid) { return done(null, false, { message: 'Incorrect username or password.' }) } diff --git a/server/src/types/passport-google-oidc.d.ts b/server/src/types/passport-google-oidc.d.ts new file mode 100644 index 0000000..6e26fdd --- /dev/null +++ b/server/src/types/passport-google-oidc.d.ts @@ -0,0 +1,25 @@ +/* eslint-disable no-unused-vars */ +declare module 'passport-google-oidc' { + // Add specific type declarations here as needed. + // For example, if you're only using it as a middleware in Express: + import { Strategy as PassportStrategy } from 'passport' + import { Request } from 'express' + + interface StrategyOptions { + clientID: string + clientSecret: string + callbackURL: string + } + + interface VerifyFunction { + ( + issuer: string, + profile: any, + done: (error: any, user?: any, info?: any) => void + ): void + } + + export class Strategy extends PassportStrategy { + constructor(options: StrategyOptions, verify: VerifyFunction) + } +} diff --git a/yarn.lock b/yarn.lock index 204d7d1..6376beb 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1493,7 +1493,7 @@ __metadata: languageName: node linkType: hard -"@types/jsonwebtoken@npm:^9.0.5": +"@types/jsonwebtoken@npm:*, @types/jsonwebtoken@npm:^9.0.5": version: 9.0.5 resolution: "@types/jsonwebtoken@npm:9.0.5" dependencies: @@ -1534,7 +1534,39 @@ __metadata: languageName: node linkType: hard -"@types/passport-oauth2@npm:^1.4.15": +"@types/passport-github2@npm:^1.2.9": + version: 1.2.9 + resolution: "@types/passport-github2@npm:1.2.9" + dependencies: + "@types/express": "npm:*" + "@types/passport": "npm:*" + "@types/passport-oauth2": "npm:*" + checksum: 10c0/e4e5ecd6fe16f0b18886fd259824c0f97b4c19718b67580bbe70cc7dfa858967e90d8edf602dc0b04175ce3dd8223ae103e133060df4c6cb331809ecce5fc32c + languageName: node + linkType: hard + +"@types/passport-jwt@npm:^4.0.1": + version: 4.0.1 + resolution: "@types/passport-jwt@npm:4.0.1" + dependencies: + "@types/jsonwebtoken": "npm:*" + "@types/passport-strategy": "npm:*" + checksum: 10c0/0ced0eaa7bb379d674821108d9bc6758223f1a5f2b9790ec78d3eaaccce6a58a424cf8ed22b53d813740ec53d929e21d92cf794ef0fb30c732866750763c0d7a + languageName: node + linkType: hard + +"@types/passport-local@npm:^1.0.38": + version: 1.0.38 + resolution: "@types/passport-local@npm:1.0.38" + dependencies: + "@types/express": "npm:*" + "@types/passport": "npm:*" + "@types/passport-strategy": "npm:*" + checksum: 10c0/a8464df03f073a4bb9aef7fa7cc9e76a355f149a1148330da88346d0e9c600f845601e99ed40949a13287eacae0a7ad01cd0eb5ca00d8b81da263b1dfc3aee60 + languageName: node + linkType: hard + +"@types/passport-oauth2@npm:*, @types/passport-oauth2@npm:^1.4.15": version: 1.4.15 resolution: "@types/passport-oauth2@npm:1.4.15" dependencies: @@ -1545,6 +1577,16 @@ __metadata: languageName: node linkType: hard +"@types/passport-strategy@npm:*": + version: 0.2.38 + resolution: "@types/passport-strategy@npm:0.2.38" + dependencies: + "@types/express": "npm:*" + "@types/passport": "npm:*" + checksum: 10c0/d7d2b1782a0845bd8914250aa9213a23c8d9c2225db46d854b77f2bf0129a789f46d4a5e9ad336eca277fc7e0a051c0a2942da5c864e7c6710763f102d9d4295 + languageName: node + linkType: hard + "@types/passport@npm:*, @types/passport@npm:^1.0.16": version: 1.0.16 resolution: "@types/passport@npm:1.0.16" @@ -8492,6 +8534,9 @@ __metadata: "@types/express-session": "npm:^1.17.10" "@types/jsonwebtoken": "npm:^9.0.5" "@types/passport": "npm:^1.0.16" + "@types/passport-github2": "npm:^1.2.9" + "@types/passport-jwt": "npm:^4.0.1" + "@types/passport-local": "npm:^1.0.38" "@types/passport-oauth2": "npm:^1.4.15" "@types/validator": "npm:^13.11.9" bcrypt: "npm:^5.1.1"