Skip to content

Commit 4db3ab6

Browse files
Copilotalexanmtz
andauthored
Refactor passport configuration into modular strategy files (#1372)
* Initial plan * Refactor passport: Move strategies to separate files in src/client/auth Co-authored-by: alexanmtz <88840+alexanmtz@users.noreply.github.com> * Remove old passport.ts from config directory after successful refactoring Co-authored-by: alexanmtz <88840+alexanmtz@users.noreply.github.com> --------- Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com> Co-authored-by: alexanmtz <88840+alexanmtz@users.noreply.github.com>
1 parent ec4a914 commit 4db3ab6

9 files changed

Lines changed: 424 additions & 341 deletions

File tree

Lines changed: 85 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,85 @@
1+
import { Strategy as BitbucketStrategy } from 'passport-bitbucket-oauth20'
2+
import jwt from 'jsonwebtoken'
3+
import requestPromise from 'request-promise'
4+
import { bitbucket, oauthCallbacks } from '../../config/secrets'
5+
import { userExists, userBuilds, userUpdate } from '../../modules/users'
6+
import { mailChimpConnect } from '../mail/mailchimp'
7+
8+
interface UserData {
9+
id?: number
10+
provider?: string
11+
social_id?: string
12+
name?: string
13+
username?: string
14+
picture_url?: string
15+
website?: string
16+
repos?: number
17+
email?: string
18+
token?: string
19+
}
20+
21+
export const createBitbucketStrategy = () => {
22+
if (!bitbucket.id || !bitbucket.secret) {
23+
return null
24+
}
25+
26+
return new BitbucketStrategy(
27+
{
28+
clientID: bitbucket.id,
29+
clientSecret: bitbucket.secret,
30+
callbackURL: oauthCallbacks.bitbucketCallbackUrl
31+
},
32+
async (accessToken: string, accessTokenSecret: string, profile: any, done: any) => {
33+
try {
34+
const data: UserData = {
35+
provider: profile.provider,
36+
social_id: profile.id,
37+
name: profile.displayName,
38+
username: profile.username,
39+
picture_url: profile._json.links.avatar.href,
40+
website: profile._json.website,
41+
repos: 0,
42+
email: profile.emails[0].value
43+
}
44+
45+
try {
46+
const response = await requestPromise({
47+
uri: `https://api.bitbucket.org/2.0/repositories/${profile.username}`,
48+
headers: {
49+
authorization: `Bearer ${accessToken}`
50+
}
51+
})
52+
53+
data.repos = JSON.parse(response).size
54+
const user = await userExists(data)
55+
56+
if (user) {
57+
await userUpdate({ ...data, id: user.id })
58+
const token = jwt.sign(
59+
{ id: data.id, email: data.email },
60+
process.env.SECRET_PHRASE as string
61+
)
62+
data.token = token
63+
return done(null, data)
64+
} else {
65+
const newUser = await userBuilds(data)
66+
mailChimpConnect(profile.emails[0].value)
67+
return done(null, newUser)
68+
}
69+
} catch (e) {
70+
// eslint-disable-next-line no-console
71+
console.log('Error fetching Bitbucket repositories')
72+
// eslint-disable-next-line no-console
73+
console.log(e)
74+
return done(null)
75+
}
76+
} catch (error) {
77+
// eslint-disable-next-line no-console
78+
console.log('Error in bitbucket-strategy.ts configuration file - search users')
79+
// eslint-disable-next-line no-console
80+
console.log(error)
81+
return done(null)
82+
}
83+
}
84+
)
85+
}
Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
import { Strategy as FacebookStrategy } from 'passport-facebook'
2+
import { facebook, oauthCallbacks } from '../../config/secrets'
3+
import { userExists, userBuilds, userUpdate } from '../../modules/users'
4+
5+
interface UserData {
6+
id?: number
7+
provider?: string
8+
social_id?: string
9+
profile?: any
10+
attribute?: any
11+
email?: string
12+
}
13+
14+
export const createFacebookStrategy = () => {
15+
if (!facebook.id || !facebook.secret) {
16+
return null
17+
}
18+
19+
return new FacebookStrategy(
20+
{
21+
clientID: facebook.id,
22+
clientSecret: facebook.secret,
23+
callbackURL: oauthCallbacks.facebookCallbackUrl
24+
},
25+
async (accessToken, accessTokenSecret, profile, done) => {
26+
try {
27+
const attributes = {
28+
access_token: accessToken,
29+
access_token_secret: accessTokenSecret
30+
}
31+
32+
const data: UserData = {
33+
provider: 'facebook',
34+
social_id: profile.id,
35+
profile: profile,
36+
attribute: attributes,
37+
email: 'Checking a facebook setup'
38+
}
39+
40+
const user = await userExists(data)
41+
if (user) {
42+
const updatedUser = await userUpdate({ ...data, id: user.id })
43+
return done(null, updatedUser)
44+
} else {
45+
const newUser = await userBuilds(data)
46+
return done(null, newUser)
47+
}
48+
} catch (error) {
49+
// eslint-disable-next-line no-console
50+
console.log('Error in facebook-strategy.ts configuration file')
51+
// eslint-disable-next-line no-console
52+
console.log(error)
53+
return done(null)
54+
}
55+
}
56+
)
57+
}

src/client/auth/github-strategy.ts

Lines changed: 114 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,114 @@
1+
import { Strategy as GitHubStrategy } from 'passport-github2'
2+
import jwt from 'jsonwebtoken'
3+
import requestPromise from 'request-promise'
4+
import { github, oauthCallbacks } from '../../config/secrets'
5+
import { userExists, userBuilds, userUpdate } from '../../modules/users'
6+
import { mailChimpConnect } from '../mail/mailchimp'
7+
8+
interface UserData {
9+
id?: number
10+
provider?: string
11+
provider_username?: string
12+
provider_id?: string
13+
provider_email?: string
14+
name?: string
15+
username?: string
16+
picture_url?: string
17+
website?: string
18+
profile_url?: string
19+
repos?: number
20+
email?: string
21+
login_strategy?: string
22+
token?: string
23+
}
24+
25+
export const createGitHubStrategy = () => {
26+
if (!github.id || !github.secret) {
27+
return null
28+
}
29+
30+
return new GitHubStrategy(
31+
{
32+
clientID: github.id,
33+
clientSecret: github.secret,
34+
callbackURL: oauthCallbacks.githubCallbackUrl,
35+
passReqToCallback: true,
36+
scope: ['user:email', 'read:org']
37+
},
38+
async (req: any, accessToken: string, accessTokenSecret: string, profile: any, done: any) => {
39+
try {
40+
const githubEmail = profile.emails ? profile.emails[0].value : profile._json.email
41+
const userEmail = req.query.state
42+
const email = userEmail || githubEmail
43+
44+
const data: UserData = {
45+
provider: profile.provider,
46+
provider_username: profile.username,
47+
provider_id: profile.id,
48+
provider_email: githubEmail,
49+
name: profile.displayName,
50+
username: profile.username,
51+
picture_url: profile.photos[0].value,
52+
website: profile._json.blog,
53+
profile_url: profile.profileUrl,
54+
repos: 0,
55+
email: email
56+
}
57+
58+
if (userEmail) {
59+
data.login_strategy = 'local'
60+
} else {
61+
data.login_strategy = 'github'
62+
}
63+
64+
if (!email) {
65+
return done(null)
66+
}
67+
68+
try {
69+
const response = await requestPromise({
70+
uri: `https://api.github.com/users/${profile.username}/repos`,
71+
headers: {
72+
'User-Agent': 'octonode/0.3 (https://github.com/pksunkara/octonode) terminal/0.0',
73+
authorization: `token ${accessToken}`
74+
}
75+
})
76+
77+
data.repos = JSON.parse(response).length
78+
const user = await userExists(data)
79+
80+
if (user) {
81+
await userUpdate({ ...data, id: user.id })
82+
const token = jwt.sign(
83+
{ id: data.id, email: data.email },
84+
process.env.SECRET_PHRASE as string
85+
)
86+
data.token = token
87+
return done(null, data)
88+
} else {
89+
await userBuilds(data)
90+
const token = jwt.sign(
91+
{ id: data.id, email: data.email },
92+
process.env.SECRET_PHRASE as string
93+
)
94+
data.token = token
95+
mailChimpConnect(data.email as string)
96+
return done(null, data)
97+
}
98+
} catch (e) {
99+
// eslint-disable-next-line no-console
100+
console.log('Error fetching GitHub repositories')
101+
// eslint-disable-next-line no-console
102+
console.log(e)
103+
return done(null)
104+
}
105+
} catch (error) {
106+
// eslint-disable-next-line no-console
107+
console.log('Error in github-strategy.ts configuration file - search users')
108+
// eslint-disable-next-line no-console
109+
console.log(error)
110+
return done(null)
111+
}
112+
}
113+
)
114+
}

src/client/auth/google-strategy.ts

Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
import { Strategy as GoogleStrategy } from 'passport-google-oauth20'
2+
import { google, oauthCallbacks } from '../../config/secrets'
3+
import { userExists, userBuilds, userUpdate } from '../../modules/users'
4+
5+
interface UserData {
6+
id?: number
7+
provider?: string
8+
social_id?: string
9+
profile?: any
10+
attribute?: any
11+
email?: string
12+
}
13+
14+
export const createGoogleStrategy = () => {
15+
if (!google.id || !google.secret) {
16+
return null
17+
}
18+
19+
return new GoogleStrategy(
20+
{
21+
clientID: google.id,
22+
clientSecret: google.secret,
23+
callbackURL: oauthCallbacks.googleCallbackUrl
24+
},
25+
async (accessToken, refreshToken, profile, done) => {
26+
try {
27+
const attributes = {
28+
access_token: accessToken,
29+
refresh_token: refreshToken
30+
}
31+
32+
const data: UserData = {
33+
provider: 'google',
34+
social_id: profile.id,
35+
profile: profile,
36+
attribute: attributes,
37+
email: profile.emails?.[0]?.value
38+
}
39+
40+
const user = await userExists(data)
41+
if (user) {
42+
const updatedUser = await userUpdate({ ...data, id: user.id })
43+
return done(null, updatedUser)
44+
} else {
45+
const newUser = await userBuilds(data)
46+
return done(null, newUser)
47+
}
48+
} catch (error) {
49+
// eslint-disable-next-line no-console
50+
console.log('Error in google-strategy.ts configuration file')
51+
// eslint-disable-next-line no-console
52+
console.log(error)
53+
return done(null)
54+
}
55+
}
56+
)
57+
}

src/client/auth/jwt-strategy.ts

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
import passportJWT from 'passport-jwt'
2+
import { userExists } from '../../modules/users'
3+
4+
const ExtractJWT = passportJWT.ExtractJwt
5+
const JWTStrategy = passportJWT.Strategy
6+
7+
export const createJWTStrategy = () => {
8+
if (!process.env.SECRET_PHRASE) {
9+
return null
10+
}
11+
12+
return new JWTStrategy(
13+
{
14+
jwtFromRequest: ExtractJWT.fromAuthHeaderAsBearerToken(),
15+
secretOrKey: process.env.SECRET_PHRASE
16+
},
17+
async (jwtPayload: any, done: any) => {
18+
try {
19+
const userAttributes = {
20+
email: jwtPayload.email
21+
}
22+
const user = await userExists(userAttributes)
23+
if (!user) return done(null, false)
24+
return done(null, user)
25+
} catch (error) {
26+
return done(error)
27+
}
28+
}
29+
)
30+
}

src/client/auth/local-strategy.ts

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
import { Strategy as LocalStrategy } from 'passport-local'
2+
import jwt from 'jsonwebtoken'
3+
import { userExists } from '../../modules/users'
4+
5+
export const createLocalStrategy = () => {
6+
return new LocalStrategy(async function verify(username, password, done) {
7+
const userAttributes = {
8+
email: username
9+
}
10+
try {
11+
const user = await userExists(userAttributes)
12+
if (!user) return done(null, false)
13+
if (user.login_strategy && user.login_strategy !== 'local') return done(null, false)
14+
if (user.verifyPassword && user.verifyPassword(password, user.password as string)) {
15+
const token = jwt.sign(
16+
{ id: user.id, email: user.email },
17+
process.env.SECRET_PHRASE as string
18+
)
19+
user.token = token
20+
return done(null, user)
21+
}
22+
return done(null, false)
23+
} catch (err) {
24+
console.log('err', err)
25+
return done(err)
26+
}
27+
})
28+
}

0 commit comments

Comments
 (0)