Skip to content
This repository was archived by the owner on Mar 13, 2025. It is now read-only.

Commit d7b5e6a

Browse files
committed
Preliminary Azure Devops support
1 parent baf6c04 commit d7b5e6a

20 files changed

+1155
-20
lines changed

certs/nginx-selfsigned.crt

+21
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
-----BEGIN CERTIFICATE-----
2+
MIIDdTCCAl2gAwIBAgIUXZRXuC8geqyvofW3Lf/Vq97o2cIwDQYJKoZIhvcNAQEL
3+
BQAwSjELMAkGA1UEBhMCVVMxEzARBgNVBAgMClNvbWUtU3RhdGUxETAPBgNVBAoM
4+
CFRvcGNvZGVyMRMwEQYDVQQDDAp0b3Bjb2Rlci14MB4XDTIwMDMzMTEyNDUzNVoX
5+
DTIxMDMzMTEyNDUzNVowSjELMAkGA1UEBhMCVVMxEzARBgNVBAgMClNvbWUtU3Rh
6+
dGUxETAPBgNVBAoMCFRvcGNvZGVyMRMwEQYDVQQDDAp0b3Bjb2Rlci14MIIBIjAN
7+
BgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAobG89/+fnyOK9iQb7LSK6wz/qxJr
8+
RejnAjUqqkcWUMtpyi7slCIZByVVMwiCoZlJbkuBZocdRc8ZLdNLDg+M5PPRA+dz
9+
ZDA3c3qL1mMjSeEwixt8es4Pl//KyWk7QBPfwzVetncAOVr6p9F7nuFBabaDtJjg
10+
gjaAA0QTwnrrr9LL7qjcJBd0V9Sgw18AaNxY9Sj5K3qbFj7/oHddt4etavUqhOdB
11+
OdWc2WCqdHSqyzoRnp1opg3mKicGom/wOH4kkBdDX6g3qTtbTcmR5An81Per1FYV
12+
0D7TXJgK2rUMRPde4d2jPi+KjdDldoy5XODokdililVbde5IAEZ5K0aiJQIDAQAB
13+
o1MwUTAdBgNVHQ4EFgQU4tg6EI8GVJpE5S6owg9n0/be+RowHwYDVR0jBBgwFoAU
14+
4tg6EI8GVJpE5S6owg9n0/be+RowDwYDVR0TAQH/BAUwAwEB/zANBgkqhkiG9w0B
15+
AQsFAAOCAQEAAgOFnD/RWZ73Vgih5gRkYbiqxCgIM1wsnEf48OFogmD8RiYffaCa
16+
uB7KzMEwJTHTUgAqqNbV6jmtYxwoXGRkEr61gRNliVmNTRDOxa6DWaN9OYRBDr+3
17+
d94/V4htel+FnYWQcejoafAAEuBJVyzaIA0lmU1sjKQmMRwHGgFTwwPOw4zwyxxu
18+
T8gnUO1ib/cFUHiYUAKnW93jKXyZNi8JRczKoX3Guu8iHCJ1z4fTNvUEsImLSuug
19+
OXFyPbfu7HHX7UiLJX8EP9lJDfQ+IVSNbaxYxHsP2iiB4FISfuK9VmO3+lmaxHI1
20+
diwNfj74dpae4wVl1HX523L3tkZQoQmPbA==
21+
-----END CERTIFICATE-----

certs/nginx-selfsigned.key

+28
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
-----BEGIN PRIVATE KEY-----
2+
MIIEvwIBADANBgkqhkiG9w0BAQEFAASCBKkwggSlAgEAAoIBAQChsbz3/5+fI4r2
3+
JBvstIrrDP+rEmtF6OcCNSqqRxZQy2nKLuyUIhkHJVUzCIKhmUluS4Fmhx1Fzxkt
4+
00sOD4zk89ED53NkMDdzeovWYyNJ4TCLG3x6zg+X/8rJaTtAE9/DNV62dwA5Wvqn
5+
0Xue4UFptoO0mOCCNoADRBPCeuuv0svuqNwkF3RX1KDDXwBo3Fj1KPkrepsWPv+g
6+
d123h61q9SqE50E51ZzZYKp0dKrLOhGenWimDeYqJwaib/A4fiSQF0NfqDepO1tN
7+
yZHkCfzU96vUVhXQPtNcmAratQxE917h3aM+L4qN0OV2jLlc4OiR2KWKVVt17kgA
8+
RnkrRqIlAgMBAAECggEBAJq2SRx171JCnOzlIf77xMwgtOUIC7Jppde77WXd/OEz
9+
sLZu7ZjTg2UN+JaK9wsOc29gOaFTeNPZ07rAKFl80ZAkJoL4y7U6WWRaBkEMvLAt
10+
EtiXZSTP06XZbzwGP1YRbhIHF+e4t3MptRor23/rAj7XDvAXMwIEiboWQl3cZXTl
11+
1TQdq8ABhhbg5p8fcZvzDasbi8NnyOs0dszHh53IReuqgvhxt8sxH9XKCZHak8Zu
12+
r4cpN1a3jFb6R43oyCYCVlnWzu9pjbZYtZrsaRAmk1PHnATbfQde61gjavV7lc6Y
13+
0R2fne6tMzjK4LnA6da2CvlGTWObo5pByEhFNm0IYOECgYEAzYNzyG9rb1dzkGUt
14+
DiZAJetfJjljBDpkow+J4LudXFFC+Pd+OQYwRS2SRIMKLPaFET3K9Bou0e6R+P+n
15+
cf18RW1t9xEFHFgUt+CdzQo7IkRMNj+iUo6kkpQKhGdncAfrxDWahGXRJycfkzpJ
16+
EZFpQt7atY1fYBn8BRujVh8z5I0CgYEAyWqJzzLxIJn6dxIeKvXLrRM68zSjbd/1
17+
WMS3d51Dc2XEaDA5kn7/G59OZAAOHmk74OpIxpR5QOzydEGhjNJ3HWecEl8vfYq2
18+
UDHCMz81yZWqvuVtVANsKshevmF6EkdMR62q61j8lbKDFcV1G7GeGwIHETc+Ahh+
19+
edW785It6fkCgYAnsYYBZpPHk4p8jy4el4C4Uje0eE0JmgWqAOxOfa4tEHzw/Uxh
20+
0zIrilu/49dpS8vzwo2ajBwS7BNBlo9O0vjXqAUfPShRiymlQjr4SUuWmL5nk+7U
21+
JzzeGr3VSOuPldgRs5C+lbPJ7iKJGy7Vt9Iu2kA/5KhRNXOZwPbRQYGSWQKBgQCU
22+
x4fIb97BsDvdHJsALNQoop3W7LkT/mzjB1xmlNowMaolNAoy9nBG3SQwpgHH4QAE
23+
IctkNGRk2yI1Ug2dUhH+vHwC7iDMYVxOXJMQ+84le9LGc/6QIn8SEzQ4+RQM0HG+
24+
OMCaW/8oLNa7jEH3FPqvBI5n3yCEt8clBAZz4zTbMQKBgQCChOHosnIo789xqVej
25+
cmOpMSkFfosR53IoCwIgsNOSMQEqAVBNN1l2p+7zYH3WqBQLml2MqZgDlEPMrNqS
26+
ZI607uP1uwCAHZDDvkNCVY4e0vXAjXxha0MfE10fQX+lwNzcTSATgivQoJu8NEuU
27+
6rPnc5poMEcSlopRThUR3obQfA==
28+
-----END PRIVATE KEY-----

scripts/nginx.conf

+22
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
error_log /dev/stdout info;
2+
3+
events {}
4+
http {
5+
access_log /dev/stdout;
6+
server {
7+
listen 443 ssl;
8+
server_name topcoderx.topcoder-dev.com;
9+
10+
ssl_certificate ../certs/nginx-selfsigned.crt;
11+
ssl_certificate_key ../certs/nginx-selfsigned.key;
12+
13+
location / {
14+
proxy_pass http://localhost:80;
15+
proxy_http_version 1.1;
16+
proxy_set_header Upgrade $http_upgrade;
17+
proxy_set_header Connection 'upgrade';
18+
proxy_set_header Host $host;
19+
proxy_cache_bypass $http_upgrade;
20+
}
21+
}
22+
}

src/common/constants.js

+11
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@ const USER_ROLES = {
3131
const USER_TYPES = {
3232
GITHUB: 'github',
3333
GITLAB: 'gitlab',
34+
AZURE: 'azure'
3435
};
3536

3637
// The default page size for Gitlab API
@@ -49,8 +50,15 @@ const GITLAB_ACCESS_TOKEN_DEFAULT_EXPIRATION = 3600 * 24 * 14;
4950
// The Gitlab refresh token time in seconds before expiration
5051
const GITLAB_REFRESH_TOKEN_BEFORE_EXPIRATION = 300;
5152

53+
// The Azure access token default expiration in seconds
54+
const AZURE_ACCESS_TOKEN_DEFAULT_EXPIRATION = 3600 * 24 * 14;
55+
56+
// The Azure refresh token time in seconds before expiration
57+
const AZURE_REFRESH_TOKEN_BEFORE_EXPIRATION = 300;
58+
5259
const GITHUB_OWNER_CALLBACK_URL = '/api/v1/github/owneruser/callback';
5360
const GITLAB_OWNER_CALLBACK_URL = '/api/v1/gitlab/owneruser/callback';
61+
const AZURE_OWNER_CALLBACK_URL = '/api/v1/azure/owneruser/callback';
5462

5563
const OWNER_USER_LOGIN_SUCCESS_URL = '/#!/app/settings';
5664
const USER_ADDED_TO_TEAM_SUCCESS_URL = '/#!/members';
@@ -70,8 +78,11 @@ module.exports = {
7078
GITLAB_DEFAULT_GROUP_ACCESS_LEVEL,
7179
GITLAB_ACCESS_TOKEN_DEFAULT_EXPIRATION,
7280
GITLAB_REFRESH_TOKEN_BEFORE_EXPIRATION,
81+
AZURE_ACCESS_TOKEN_DEFAULT_EXPIRATION,
82+
AZURE_REFRESH_TOKEN_BEFORE_EXPIRATION,
7383
GITHUB_OWNER_CALLBACK_URL,
7484
GITLAB_OWNER_CALLBACK_URL,
85+
AZURE_OWNER_CALLBACK_URL,
7586
OWNER_USER_LOGIN_SUCCESS_URL,
7687
USER_ADDED_TO_TEAM_SUCCESS_URL,
7788
TC_LOGIN_CALLBACK_URL,

src/common/helper.js

+30-5
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ const NotFoundError = require('./errors').NotFoundError;
2525
const ValidationError = require('./errors').ValidationError;
2626
const dbHelper = require('./db-helper');
2727

28+
2829
bluebird.promisifyAll(bcrypt);
2930
bluebird.promisifyAll(parseDomain);
3031

@@ -201,7 +202,8 @@ async function ensureExists(Model, criteria, modelName) {
201202
*/
202203
async function getProviderType(repoUrl) {
203204
const parsedDomain = await parseDomain(repoUrl);
204-
if (!parsedDomain || !parsedDomain.domain || (parsedDomain.domain !== 'github' && parsedDomain.domain !== 'gitlab')) {
205+
if (!parsedDomain || !parsedDomain.domain ||
206+
(parsedDomain.domain !== 'github' && parsedDomain.domain !== 'gitlab' && parsedDomain.domain !== 'azure')) {
205207
throw new ValidationError('Invalid git repo url');
206208
}
207209
return parsedDomain.domain;
@@ -220,16 +222,26 @@ async function getProjectCopilotOrOwner(models, project, provider, isCopilot) {
220222
topcoderUsername: isCopilot ? project.copilot : project.owner,
221223
});
222224

223-
if (!userMapping || (provider === 'github' && !userMapping.githubUserId) || (provider === 'gitlab' && !userMapping.gitlabUserId)) {
225+
if (!userMapping ||
226+
(provider === 'github' && !userMapping.githubUserId)
227+
|| (provider === 'gitlab' && !userMapping.gitlabUserId)
228+
|| (provider === 'azure' && !userMapping.azureUserId)) {
224229
throw new Error(`Couldn't find ${isCopilot ? 'copilot' : 'owner'} username for '${provider}' for this repository.`);
225230
}
226231

227-
return await dbHelper.scanOne(models.User, {
228-
username: provider === 'github' ? userMapping.githubUsername : userMapping.gitlabUsername,
232+
let user = await dbHelper.scanOne(models.User, {
233+
username: provider === 'github' ? userMapping.githubUsername : // eslint-disable-line no-nested-ternary
234+
provider === 'gitlab' ? userMapping.gitlabUsername : userMapping.azureEmail,
229235
type: provider,
230236
});
231-
}
237+
238+
if (provider === 'azure') {
239+
const azureService = require('../services/AzureService'); // eslint-disable-line global-require
240+
user = azureService.refreshAzureUserAccessToken(user);
241+
}
232242

243+
return user;
244+
}
233245

234246
/**
235247
* Generate an unique identifier
@@ -240,6 +252,18 @@ function generateIdentifier() {
240252
return `${uuid()}-${new Date().getTime()}`;
241253
}
242254

255+
/**
256+
* Generate simple hash of string
257+
*
258+
* @param {String} s the str
259+
* @returns {String} the hash
260+
*/
261+
function hashCode(s) {
262+
return s.split("").reduce(function(a, b){
263+
a = ((a << 5) - a) + b.charCodeAt(0); // eslint-disable-line no-bitwise, no-magic-numbers
264+
return a & a; // eslint-disable-line no-bitwise
265+
}, 0);
266+
}
243267

244268
module.exports = {
245269
buildService,
@@ -250,4 +274,5 @@ module.exports = {
250274
generateIdentifier,
251275
getProviderType,
252276
getProjectCopilotOrOwner,
277+
hashCode
253278
};

src/config.js

+19-5
Original file line numberDiff line numberDiff line change
@@ -15,14 +15,22 @@ module.exports = {
1515
// MONGODB_URI: process.env.MONGODB_URI || 'mongodb://localhost:27017/topcoderx',
1616
SESSION_SECRET: process.env.SESSION_SECRET || 'kjsdfkj34857',
1717
// Github and gitlab client id and secret
18-
GITHUB_CLIENT_ID: process.env.GITHUB_CLIENT_ID || ' ',
19-
GITHUB_CLIENT_SECRET: process.env.GITHUB_CLIENT_SECRET || ' ',
20-
GITLAB_CLIENT_ID: process.env.GITLAB_CLIENT_ID || ' ',
21-
GITLAB_CLIENT_SECRET: process.env.GITLAB_CLIENT_SECRET || ' ',
22-
18+
GITHUB_CLIENT_ID: process.env.GITHUB_CLIENT_ID,
19+
GITHUB_CLIENT_SECRET: process.env.GITHUB_CLIENT_SECRET,
20+
GITLAB_CLIENT_ID: process.env.GITLAB_CLIENT_ID,
21+
GITLAB_CLIENT_SECRET: process.env.GITLAB_CLIENT_SECRET,
22+
AZURE_APP_ID: process.env.AZURE_APP_ID,
23+
AZURE_CLIENT_SECRET: process.env.AZURE_CLIENT_SECRET,
24+
AZURE_USER_APP_ID: process.env.AZURE_APP_ID,
25+
AZURE_USER_CLIENT_SECRET: process.env.AZURE_USER_CLIENT_SECRET,
26+
2327
// used as base to construct various URLs
2428
WEBSITE: process.env.WEBSITE || 'http://topcoderx.topcoder-dev.com',
29+
WEBSITE_SECURE: process.env.WEBSITE_SECURE || 'https://topcoderx.topcoder-dev.com',
2530
GITLAB_API_BASE_URL: process.env.GITLAB_API_BASE_URL || 'https://gitlab.com',
31+
AZURE_API_BASE_URL: process.env.AZURE_API_BASE_URL || 'https://app.vssps.visualstudio.com',
32+
AZURE_DEVOPS_API_BASE_URL: process.env.AZURE_DEVOPS_API_BASE_URL || 'https://dev.azure.com',
33+
2634
// kafka configuration
2735
TOPIC: process.env.TOPIC || 'tc-x-events',
2836
KAFKA_OPTIONS: {
@@ -82,6 +90,7 @@ const frontendConfigs = {
8290
"DIRECT_URL_BASE": "https://www.topcoder-dev/direct/projectOverview?formData.projectId=",
8391
"OWNER_LOGIN_GITHUB_URL":"/api/v1/github/owneruser/login",
8492
"OWNER_LOGIN_GITLAB_URL":"/api/v1/gitlab/owneruser/login",
93+
"OWNER_LOGIN_AZURE_URL":"/api/v1/azure/owneruser/login",
8594
"TOPCODER_URL": "https://topcoder-dev.com",
8695
"GITHUB_TEAM_URL": "https://github.com/orgs/",
8796
"GITLAB_GROUP_URL": "https://gitlab.com/groups/"
@@ -99,6 +108,7 @@ const frontendConfigs = {
99108
"DIRECT_URL_BASE": "https://www.topcoder-dev.com/direct/projectOverview?formData.projectId=",
100109
"OWNER_LOGIN_GITHUB_URL":"/api/v1/github/owneruser/login",
101110
"OWNER_LOGIN_GITLAB_URL":"/api/v1/gitlab/owneruser/login",
111+
"OWNER_LOGIN_AZURE_URL":"/api/v1/azure/owneruser/login",
102112
"TOPCODER_URL": "https://topcoder-dev.com",
103113
"GITHUB_TEAM_URL": "https://github.com/orgs/",
104114
"GITLAB_GROUP_URL": "https://gitlab.com/groups/"
@@ -115,6 +125,7 @@ const frontendConfigs = {
115125
"DIRECT_URL_BASE": "https://www.topcoder-dev.com/direct/projectOverview?formData.projectId=",
116126
"OWNER_LOGIN_GITHUB_URL":"/api/v1/github/owneruser/login",
117127
"OWNER_LOGIN_GITLAB_URL":"/api/v1/gitlab/owneruser/login",
128+
"OWNER_LOGIN_AZURE_URL":"/api/v1/azure/owneruser/login",
118129
"TOPCODER_URL": "https://topcoder-dev.com",
119130
"GITHUB_TEAM_URL": "https://github.com/orgs/",
120131
"GITLAB_GROUP_URL": "https://gitlab.com/groups/"
@@ -131,6 +142,7 @@ const frontendConfigs = {
131142
"DIRECT_URL_BASE": "https://www.topcoder-dev.com/direct/projectOverview?formData.projectId=",
132143
"OWNER_LOGIN_GITHUB_URL":"/api/v1/github/owneruser/login",
133144
"OWNER_LOGIN_GITLAB_URL":"/api/v1/gitlab/owneruser/login",
145+
"OWNER_LOGIN_AZURE_URL":"/api/v1/azure/owneruser/login",
134146
"TOPCODER_URL": "https://topcoder-dev.com",
135147
"GITHUB_TEAM_URL": "https://github.com/orgs/",
136148
"GITLAB_GROUP_URL": "https://gitlab.com/groups/"
@@ -147,6 +159,7 @@ const frontendConfigs = {
147159
"DIRECT_URL_BASE": "https://www.topcoder.com/direct/projectOverview?formData.projectId=",
148160
"OWNER_LOGIN_GITHUB_URL":"/api/v1/github/owneruser/login",
149161
"OWNER_LOGIN_GITLAB_URL":"/api/v1/gitlab/owneruser/login",
162+
"OWNER_LOGIN_AZURE_URL":"/api/v1/azure/owneruser/login",
150163
"TOPCODER_URL": "https://topcoder-dev.com",
151164
"GITHUB_TEAM_URL": "https://github.com/orgs/",
152165
"GITLAB_GROUP_URL": "https://gitlab.com/groups/"
@@ -169,6 +182,7 @@ module.exports.frontendConfigs = {
169182
DIRECT_URL_BASE: process.env.DIRECT_URL_BASE || frontendConfigs[activeEnv].DIRECT_URL_BASE,
170183
OWNER_LOGIN_GITHUB_URL: process.env.OWNER_LOGIN_GITHUB_URL || frontendConfigs[activeEnv].OWNER_LOGIN_GITHUB_URL,
171184
OWNER_LOGIN_GITLAB_URL: process.env.OWNER_LOGIN_GITLAB_URL || frontendConfigs[activeEnv].OWNER_LOGIN_GITLAB_URL,
185+
OWNER_LOGIN_AZURE_URL: process.env.OWNER_LOGIN_AZURE_URL || frontendConfigs[activeEnv].OWNER_LOGIN_AZURE_URL,
172186
TOPCODER_URL: process.env.TOPCODER_URL || frontendConfigs[activeEnv].TOPCODER_URL,
173187
GITHUB_TEAM_URL: process.env.GITHUB_TEAM_URL || frontendConfigs[activeEnv].GITHUB_TEAM_URL,
174188
GITLAB_GROUP_URL: process.env.GITLAB_GROUP_URL || frontendConfigs[activeEnv].GITLAB_GROUP_URL

0 commit comments

Comments
 (0)