Skip to content

feat: primary role #333

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 12 commits into from
Mar 16, 2023
2 changes: 1 addition & 1 deletion .circleci/config.yml
Original file line number Diff line number Diff line change
@@ -70,7 +70,7 @@ workflows:
branches:
only:
- dev
- jira-plat-742
- feature/primary-role

# Production builds are exectuted only on tagged commits to the
# master branch.
173 changes: 53 additions & 120 deletions web-assets/auth0/dev-tenant/database/create.js
Original file line number Diff line number Diff line change
@@ -21,133 +21,66 @@
// callback(new ValidationError("user_exists", "my error message"));
// 3. Something went wrong while trying to reach your database
// callback(new Error("my error message"));
const msg = 'Please implement the Create script for this database connection ' +
'at https://manage.auth0.com/#/connections/database';
return callback(new Error(msg)); */
function create(user, callback) {
//console.log("landed here...................................");
var countryObj = JSON.parse(user.user_metadata.country);
var regSource = user.user_metadata.reg_source;
var utmSource = user.user_metadata.utm_source;
var utmMedium = user.user_metadata.utm_medium;
var utmCampaign = user.user_metadata.utm_campaign;
var retUrl = user.user_metadata.returnUrl;
var afterActivationURL =
retUrl !== null ? retUrl : "https://" + configuration.DOMAIN + "/home";
if (regSource === configuration.REG_BUSINESS) {
afterActivationURL = "https://connect." + configuration.DOMAIN;
}
var data = {
param: {
handle: user.username,
email: user.email,
credential: {
password: user.password,
},
firstName: user.user_metadata.firstName,
lastName: user.user_metadata.lastName,
country: {
code: countryObj.code,
isoAlpha3Code: countryObj.alpha3,
isoAlpha2Code: countryObj.alpha2,
},
regSource: regSource,
utmSource: utmSource,
utmMedium: utmMedium,
utmCampaign: utmCampaign,
},
options: {
afterActivationURL: encodeURIComponent(afterActivationURL),
},
};
//console.log("SignUp....", user, data);
request.post(
{
url: "https://api." + configuration.DOMAIN + "/v3/users",
json: data,
//for more options check:
//https://github.com/mikeal/request#requestoptions-callback
},
function (err, response, body) {
// console.log(err);
// console.log(response.statusCode);
// console.log(body.result.content);

if (err) return callback(err);
console.log(body.result.content);
if (response.statusCode !== 200) {
//return callback(new ValidationError("lock.fallback",body.result.content));
const error_message = body.result.content;
let code = "lock.fallback";
function create(user, callback) {

if (error_message.search("Handle may not contain a space") !== -1) {
code = "handle_invalid_space";
} else if (
error_message.search(
"Length of Handle in character should be between 2 and 15"
) !== -1
) {
code = "handle_invalid_length";
} else if (
error_message.search(
"Please choose another handle, not starting with admin"
) !== -1
) {
code = "handle_invalid_startwith_admin";
} else if (
error_message.search(
"Handle may contain only letters, numbers and"
) !== -1
) {
code = "handle_invalid_constains_forbidden_char";
} else if (
error_message.search("Handle may not contain only punctuation") !== -1
) {
code = "handle_invalid_conatins_only_punctuation";
} else if (error_message.search("The user already exists") !== -1) {
code = "user_exists";
} else if (error_message.search("has already been taken") !== -1) {
code = "user_exists";
var countryObj = JSON.parse(user.user_metadata.country);
var regSource = user.user_metadata.regSource;
var utmSource = user.user_metadata.utmSource;
var utmMedium = user.user_metadata.utmMedium;
var utmCampaign = user.user_metadata.utmCampaign;
var retUrl = user.user_metadata.returnUrl;
var afterActivationURL = retUrl ? retUrl : "https://www."+configuration.DOMAIN+"/start";
if (regSource === configuration.REG_BUSINESS) {
afterActivationURL = "https://connect."+configuration.DOMAIN;
}
var data = {
"param": {
"handle": user.username,
"email": user.email,
"credential": {
"password": user.password
},
"firstName": user.user_metadata.firstName,
"lastName": user.user_metadata.lastName,
"country": {
"code": countryObj.code,
"isoAlpha3Code": countryObj.alpha3,
"isoAlpha2Code": countryObj.alpha2
},
"primaryRole": user.user_metadata.primaryRole,
"regSource": regSource,
"utmSource": utmSource,
"utmMedium": utmMedium,
"utmCampaign": utmCampaign,
},
"options": {
"afterActivationURL": encodeURIComponent(afterActivationURL)
}
};
console.log("SignUp....", user, data);

Check failure

Code scanning / CodeQL

Clear-text logging of sensitive information

This logs sensitive data returned by [an access to password](1) as clear text. This logs sensitive data returned by [an access to password](2) as clear text.
request.post({
url: "http://api."+configuration.DOMAIN+"/v3/users",
json: data
//for more options check:
//https://github.com/mikeal/request#requestoptions-callback
}, function (err, response, body) {

return callback(new ValidationError(code, error_message));
console.log(err);
console.log(response.statusCode);
console.log(body);

//return callback(new Error(body.result.content));
}
//if (response.statusCode === 401) return callback();
/* const Analytics = require('analytics-node');
const _ = require('lodash');
var analytics = new Analytics('bkPtWMUMTYDhww2zsJluzxtdhtmSsyd9');
analytics.identify({
anonymousId: 'signup',
traits: {
user: _.omit(user, ['credential', 'password'])
}
});
analytics.track({
anonymousId: 'BXWXUWnilVUPdN01t2Se29Tw2ZYNGZvH',
event: 'signUp',
properties: _.omit(user, ['credential', 'password'])
});*/
/* const ua = require('universal-analytics');
let visitor = ua('UA-6340959-1');
visitor.pageview("/signup").send();
var eParams = {
ec: "utmCode",
ea: "tracking",
el: "tracking",
cn: utmCampaign,
cm: utmMedium,
cs: utmSource,
dp: "/signup"
};
if (err) return callback(err);

visitor.event(eParams).send(); */
callback(null);
}
); //end post request
//callback(null);
if (response.statusCode !== 200) {
return callback(new ValidationError('user_exists', body.result.content));
}
//if (response.statusCode === 401) return callback();
callback(null);
}); //end post request
//callback(null);
}

//}
//}
122 changes: 64 additions & 58 deletions web-assets/auth0/dev-tenant/rules/onboardingChecklist.js
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
function (user, context, callback) {
function OnboardingChecklist(user, context, callback) {
if (context.clientID === configuration.CLIENT_ACCOUNTS_LOGIN) {
console.log("rule:onboarding-checklist:enter");
if (context.redirect) {

if (context.redirect) {
console.log("rule:onboarding-checklist:exiting due to context being a redirect");
return callback(null, user, context);
}
@@ -24,10 +24,17 @@ function (user, context, callback) {
const handle = context.idToken[global.AUTH0_CLAIM_NAMESPACE + 'handle'];
console.log("rule:onboarding-checklist: fetch onboarding_checklist for email/handle: ", user.email, handle);

if (handle == null) {
if (handle === null) {
console.log("rule:onboarding-checklist: exiting due to handle being null.");
return callback(null, user, context);
}

const roles = context.idToken[global.AUTH0_CLAIM_NAMESPACE + 'roles'];

if (roles && roles.includes('Topcoder Customer')) {
console.log("rule:onboarding-checklist:exiting due to user being a customer.");
return callback(null, user, context);
}

const createdAt = _.get(user, "created_at", null);
const thresholdDate = moment(configuration.PROFILE_CREATION_DATE_THRESHOLD, "YYYY-MM-DD");
@@ -42,14 +49,14 @@ function (user, context, callback) {
} catch (err) {
console.log("rule:onboarding-checklist: failed to compare userCreationDate", createdAt, " with threshold. Error", err);
}

/**
* Returns M2M token needed to fetch onboarding_checklist
*/
const getToken = function(callback) {
const getToken = function (callback) {
if (global.M2MToken) {
console.log('rule:onboarding-checklist:M2M token is available');
const jwt = require('jsonwebtoken');
const jwt = require('jsonwebtoken');
const decoded = jwt.decode(global.M2MToken);
const exp = moment.unix(decoded.exp);

@@ -72,7 +79,7 @@ function (user, context, callback) {
}
}, function (err, response, body) {
if (err) {
return callback(err);
return callback(err);
}

global.M2MToken = body.access_token;
@@ -81,83 +88,82 @@ function (user, context, callback) {
});
};

getToken(function(err, token) {
getToken(function (err, token) {
if (err) {
console.log('rule:onboarding-checklist:failed to fetch M2M token.');
return callback(null, user, context);
}
global.AUTH0_CLAIM_NAMESPACE = "https://" + configuration.DOMAIN + "/";
const axios = require('[email protected]');

const options = {
method: 'GET',
url: `https://api.${configuration.DOMAIN}/v5/members/${handle}/traits?traitIds=onboarding_checklist`,
headers: {
Authorization: `Bearer ${token}`
}
};

// Fetch onboarding_checklist using v5 member Api.
axios(options)
.then(result => {
try {
const data = result.data;
if (data.length === 0) {
// User doesn't have any traits with traitId onboarding_checklist and should be shown the onboarding wizard
context.idToken[global.AUTH0_CLAIM_NAMESPACE + 'onboarding_wizard'] = 'show';
console.log('rule:onboarding-checklist:Setting onboarding_wizard to show');
return callback(null, user, context);
}
.then(result => {
try {
const data = result.data;

if (data.length === 0) {
// User doesn't have any traits with traitId onboarding_checklist and should be shown the onboarding wizard
context.idToken[global.AUTH0_CLAIM_NAMESPACE + 'onboarding_wizard'] = 'show';
console.log('rule:onboarding-checklist:Setting onboarding_wizard to show');
return callback(null, user, context);
}

const onboardingChecklistTrait = data.filter((item) => item.traitId === 'onboarding_checklist')[0].traits;
let override = 'show';
for (let checklistTrait of onboardingChecklistTrait.data) {
if (checklistTrait.onboarding_wizard != null) {
if ( checklistTrait.onboarding_wizard.status !== 'pending_at_user' || // any non pending_at_user status indicates OB was either seen or completed and can be skipped
checklistTrait.onboarding_wizard.skip ||// for certain signup routes skip is set to true, and thus onboarding wizard needn't be shown
checklistTrait.onboarding_wizard.override === 'skip')
{
return callback(null, user, context);
} else if (checklistTrait.onboarding_wizard.override === 'useRetUrl') {
override = 'useRetUrl';
const onboardingChecklistTrait = data.filter((item) => item.traitId === 'onboarding_checklist')[0].traits;
let override = 'show';

for (let checklistTrait of onboardingChecklistTrait.data) {
if (checklistTrait.onboarding_wizard !== null) {
if (checklistTrait.onboarding_wizard.status !== 'pending_at_user' || // any non pending_at_user status indicates OB was either seen or completed and can be skipped
checklistTrait.onboarding_wizard.skip ||// for certain signup routes skip is set to true, and thus onboarding wizard needn't be shown
checklistTrait.onboarding_wizard.override === 'skip') {
return callback(null, user, context);
} else if (checklistTrait.onboarding_wizard.override === 'useRetUrl') {
override = 'useRetUrl';
}
}
}
}

const profileCompletedData = onboardingChecklistTrait.data.length > 0 ? onboardingChecklistTrait.data[0].profile_completed : null;

if (profileCompletedData) {
if (profileCompletedData.status === "completed") {
return callback(null, user, context);
}

for (const item in profileCompletedData.metadata) {
if (profileCompletedData.metadata[item]) {
const profileCompletedData = onboardingChecklistTrait.data.length > 0 ? onboardingChecklistTrait.data[0].profile_completed : null;

if (profileCompletedData) {
if (profileCompletedData.status === "completed") {
return callback(null, user, context);
}

for (const item in profileCompletedData.metadata) {
if (profileCompletedData.metadata[item]) {
return callback(null, user, context);
}
}
}
}

// All checks failed - indicating user newly registered and needs to be shown the onboarding wizard
console.log('rule:onboarding-checklist: set onboarding_wizard ' + override);

context.idToken[global.AUTH0_CLAIM_NAMESPACE + 'onboarding_wizard'] = override;

// All checks failed - indicating user newly registered and needs to be shown the onboarding wizard
console.log('rule:onboarding-checklist: set onboarding_wizard ' + override);

context.idToken[global.AUTH0_CLAIM_NAMESPACE + 'onboarding_wizard'] = override;



return callback(null, user, context);
} catch (e) {
console.log("rule:onboarding-checklist:Error in fetching onboarding_checklist", e);
return callback(null, user, context);
}
}).catch(requestError => {
console.log("rule:onboarding-checklist:Failed fetching onboarding_checklist with error", requestError.response.status);
return callback(null, user, context);
} catch (e) {
console.log("rule:onboarding-checklist:Error in fetching onboarding_checklist", e);
return callback(null, user, context);
}
}).catch(requestError => {
console.log("rule:onboarding-checklist:Failed fetching onboarding_checklist with error", requestError.response.status);
return callback(null, user, context);
});
});
});
} else {
return callback(null, user, context);
}
}
}
18 changes: 17 additions & 1 deletion web-assets/auth0/dev-tenant/universal-login.html
Original file line number Diff line number Diff line change
@@ -89,6 +89,13 @@
var languageDictionary;
var language;
var optionsObj = Array();
var primaryRoleOptionsObj = [{
label: 'Talent - join as a community member',
value: 'Topcoder Talent'
}, {
label: 'Customer - join to get work done',
value: 'Topcoder Customer'
}];
var regSource = config.extraParams.reg_source || null;
var utmSource = config.extraParams.utm_source || null;
var utmMedium = config.extraParams.utm_medium || null;
@@ -110,7 +117,8 @@
title: "Topcoder Login",
error: {
login: {
'lock.fallback': "We're sorry, something went wrong when attempting to log in."
'lock.fallback': "We're sorry, something went wrong when attempting to log in.",
'deactivated_account': "Account is deactivated"
},
signUp: {
"lock.fallback": "We're sorry, something went wrong when attempting to sign up.",
@@ -291,6 +299,14 @@
hint: "Must have 2 or more chars, blank spaces not allowed" // optional
};
}
},
{
type: "select",
name: "primaryRole",
placeholder: "Select your role",
options: primaryRoleOptionsObj,
fieldLabel: 'The role you select maybe changed in your Profile Settings.',
fieldPlaceholder: 'Talent join to learn, complete, connect and find freelance gig work. Customers join to launch challenges, find freelancers, and get work done.'
},
{
type: "select",
10 changes: 6 additions & 4 deletions web-assets/auth0/prod-tenant/database/create.js
Original file line number Diff line number Diff line change
@@ -50,6 +50,7 @@
"isoAlpha3Code": countryObj.alpha3,
"isoAlpha2Code": countryObj.alpha2
},
"primaryRole": user.user_metadata.primaryRole,
"regSource": regSource,
"utmSource": utmSource,
"utmMedium": utmMedium,
@@ -59,16 +60,17 @@
"afterActivationURL": encodeURIComponent(afterActivationURL)
}
};
// console.log("SignUp....", user, data);
request.post({
url: "https://api."+configuration.DOMAIN+"/v3/users",
json: data
//for more options check:
//https://github.com/mikeal/request#requestoptions-callback
}, function (err, response, body) {

console.log(err);
console.log(response.statusCode);
console.log(body);
// console.log(err);
// console.log(response.statusCode);
// console.log(body);

if (err) return callback(err);

@@ -99,4 +101,4 @@
callback(null);
}); //end post request
//callback(null);
}
}
37 changes: 22 additions & 15 deletions web-assets/auth0/prod-tenant/rules/onboardingChecklist.js
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
function (user, context, callback) {
if (context.clientID === configuration.CLIENT_ACCOUNTS_LOGIN) {
console.log("rule:onboarding-checklist:enter");
//console.log("rule:onboarding-checklist:enter");

if (context.redirect) {
console.log("rule:onboarding-checklist:exiting due to context being a redirect");
//console.log("rule:onboarding-checklist:exiting due to context being a redirect");
return callback(null, user, context);
}

@@ -13,19 +13,26 @@ function (user, context, callback) {
const isSocial = _.get(user, "identities[0].isSocial");
const connection = _.get(user, "identities[0].connection");

console.log("rule:onboarding-checklist: isSocial/connection", isSocial + "/" + connection);
console.log("rule:onboarding-checklist: WIPRO_SS_AZURE_AD_CONNECTION_NAME", configuration.WIPRO_SSO_AZURE_AD_CONNECTION_NAME);
//console.log("rule:onboarding-checklist: isSocial/connection", isSocial + "/" + connection);
//console.log("rule:onboarding-checklist: WIPRO_SS_AZURE_AD_CONNECTION_NAME", configuration.WIPRO_SSO_AZURE_AD_CONNECTION_NAME);

if (_.includes([configuration.WIPRO_SSO_AZURE_AD_CONNECTION_NAME], connection)) {
console.log("rule:onboarding-checklist:exiting due to user being an enterprise user.");
//console.log("rule:onboarding-checklist:exiting due to user being an enterprise user.");
return callback(null, user, context);
}

const handle = context.idToken[global.AUTH0_CLAIM_NAMESPACE + 'handle'];
console.log("rule:onboarding-checklist: fetch onboarding_checklist for email/handle: ", user.email, handle);
//console.log("rule:onboarding-checklist: fetch onboarding_checklist for email/handle: ", user.email, handle);

if (handle == null) {
console.log("rule:onboarding-checklist: exiting due to handle being null.");
if (handle === null) {
//console.log("rule:onboarding-checklist: exiting due to handle being null.");
return callback(null, user, context);
}

const roles = context.idToken[global.AUTH0_CLAIM_NAMESPACE + 'roles'];

if (roles && roles.includes('Topcoder Customer')) {
console.log("rule:onboarding-checklist:exiting due to user being a customer.");
return callback(null, user, context);
}

@@ -36,7 +43,7 @@ function (user, context, callback) {
// For users created before thresholdDate, we don't want to check onboarding_checklist
// This is because older profiles might not have onboarding_checklist data and they don't need to see the onboarding_wizard
if (createdAt && !thresholdDate.isBefore(moment(createdAt))) {
console.log("rule:onboarding-checklist: user created before threshold date. Not checking onboarding_checklist.");
//console.log("rule:onboarding-checklist: user created before threshold date. Not checking onboarding_checklist.");
return callback(null, user, context);
}
} catch (err) {
@@ -48,18 +55,18 @@ function (user, context, callback) {
*/
const getToken = function(callback) {
if (global.M2MToken) {
console.log('rule:onboarding-checklist:M2M token is available');
//console.log('rule:onboarding-checklist:M2M token is available');
const jwt = require('jsonwebtoken');
const decoded = jwt.decode(global.M2MToken);
const exp = moment.unix(decoded.exp);

if (exp > new Date()) {
console.log('rule:onboarding-checklist:M2M token is valid. Reusing...');
//console.log('rule:onboarding-checklist:M2M token is valid. Reusing...');
return callback(null, global.M2MToken);
}
}

console.log('rule:onboarding-checklist:Fetching new M2M token');
//console.log('rule:onboarding-checklist:Fetching new M2M token');
request.post({
url: `https://auth0proxy.${configuration.DOMAIN}/token`,
headers: 'content-type: application/json',
@@ -76,14 +83,14 @@ function (user, context, callback) {
}

global.M2MToken = body.access_token;
console.log('rule:onboarding-checklist:setting the M2MToken globally', global.M2MToken);
//console.log('rule:onboarding-checklist:setting the M2MToken globally', global.M2MToken);
return callback(null, global.M2MToken);
});
};

getToken(function(err, token) {
if (err) {
console.log('rule:onboarding-checklist:failed to fetch M2M token.');
//console.log('rule:onboarding-checklist:failed to fetch M2M token.');
return callback(null, user, context);
}
global.AUTH0_CLAIM_NAMESPACE = "https://" + configuration.DOMAIN + "/";
@@ -114,7 +121,7 @@ function (user, context, callback) {
let override = 'show';

for (let checklistTrait of onboardingChecklistTrait.data) {
if (checklistTrait.onboarding_wizard != null) {
if (checklistTrait.onboarding_wizard !== null) {
if ( checklistTrait.onboarding_wizard.status !== 'pending_at_user' || // any non pending_at_user status indicates OB was either seen or completed and can be skipped
checklistTrait.onboarding_wizard.skip ||// for certain signup routes skip is set to true, and thus onboarding wizard needn't be shown
checklistTrait.onboarding_wizard.override === 'skip')
20 changes: 18 additions & 2 deletions web-assets/auth0/prod-tenant/universal-login.html
Original file line number Diff line number Diff line change
@@ -82,6 +82,13 @@
var languageDictionary;
var language;
var optionsObj = Array();
var primaryRoleOptionsObj = [{
label: 'Talent - join as a community member',
value: 'Topcoder Talent'
}, {
label: 'Customer - join to get work done',
value: 'Topcoder Customer'
}];
var regSource = config.extraParams.reg_source || null;
var utmSource = config.extraParams.utm_source || null;
var utmMedium = config.extraParams.utm_medium || null;
@@ -104,7 +111,8 @@
title: "Topcoder Login",
error: {
login: {
'lock.fallback': "We're sorry, something went wrong when attempting to log in."
'lock.fallback': "We're sorry, something went wrong when attempting to log in.",
'deactivated_account': "Account is deactivated"
},
signUp: {
"lock.fallback": "We're sorry, something went wrong when attempting to sign up.",
@@ -188,7 +196,7 @@
socialButtonStyle: 'small'
},
tc_standard: {
allowedConnections: ['TC-User-Database', 'github', 'google-oauth2', 'wipro-adfs', 'wipro-azuread', 'Verified-User-Database'],
allowedConnections: ['TC-User-Database', 'github', 'google-oauth2', 'wipro-adfs', 'wipro-azuread', 'Verified-User-Database','TopcoderProductionGoogleWorkspace'],
theme: {
logo: 'https://i.imgur.com/IY6TVjY.png',
primaryColor: '#137d60'
@@ -332,6 +340,14 @@
};
}
},
{
type: "select",
name: "primaryRole",
placeholder: "Select your role",
options: primaryRoleOptionsObj,
fieldLabel: 'The role you select maybe changed in your Profile Settings.',
fieldPlaceholder: 'Talent join to learn, complete, connect and find freelance gig work. Customers join to launch challenges, find freelancers, and get work done.'
},
{
type: "select",
name: "country",