diff --git a/web-assets/auth0/dev-tenant/database/create.js b/web-assets/auth0/dev-tenant/database/create.js
new file mode 100644
index 0000000..c178112
--- /dev/null
+++ b/web-assets/auth0/dev-tenant/database/create.js
@@ -0,0 +1,124 @@
+/*function create(user, callback) {
+ // This script should create a user entry in your existing database. It will
+ // be executed when a user attempts to sign up, or when a user is created
+ // through the Auth0 dashboard or API.
+ // When this script has finished executing, the Login script will be
+ // executed immediately afterwards, to verify that the user was created
+ // successfully.
+ //
+ // The user object will always contain the following properties:
+ // * email: the user's email
+ // * password: the password entered by the user, in plain text
+ // * tenant: the name of this Auth0 account
+ // * client_id: the client ID of the application where the user signed up, or
+ // API key if created through the API or Auth0 dashboard
+ // * connection: the name of this database connection
+ //
+ // There are three ways this script can finish:
+ // 1. A user was successfully created
+ // callback(null);
+ // 2. This user already exists in your database
+ // 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.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 != 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";
+
+ 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";
+ }
+
+
+
+ return callback(new ValidationError(code, error_message));
+
+ //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'])
+ });*/
+ callback(null);
+ }); //end post request
+ //callback(null);
+}
+
+//}
diff --git a/web-assets/auth0/dev-tenant/database/login.js b/web-assets/auth0/dev-tenant/database/login.js
new file mode 100644
index 0000000..29fe999
--- /dev/null
+++ b/web-assets/auth0/dev-tenant/database/login.js
@@ -0,0 +1,61 @@
+function login(handleOrEmail, password, callback) {
+ // This script should authenticate a user against the credentials stored in
+ // your database.
+ // It is executed when a user attempts to log in or immediately after signing
+ // up (as a verification that the user was successfully signed up).
+ //
+ // Everything returned by this script will be set as part of the user profile
+ // and will be visible by any of the tenant admins. Avoid adding attributes
+ // with values such as passwords, keys, secrets, etc.
+ //
+ // The `password` parameter of this function is in plain text. It must be
+ // hashed/salted to match whatever is stored in your database. For example:
+ //
+ // var bcrypt = require('bcrypt@0.8.5');
+ // bcrypt.compare(password, dbPasswordHash, function(err, res)) { ... }
+ //
+ // There are three ways this script can finish:
+ // 1. The user's credentials are valid. The returned user profile should be in
+ // the following format: https://auth0.com/docs/users/normalized/auth0/normalized-user-profile-schema
+ // var profile = {
+ // user_id: ..., // user_id is mandatory
+ // email: ...,
+ // [...]
+ // };
+ // callback(null, profile);
+ // 2. The user's credentials are invalid
+ // callback(new WrongUsernameOrPasswordError(email, "my error message"));
+ // 3. Something went wrong while trying to reach your database
+ // callback(new Error("my error message"));
+ //
+ // A list of Node.js modules which can be referenced is available here:
+ //
+ // https://tehsis.github.io/webtaskio-canirequire/
+ request.post({
+ url: "https://api."+configuration.DOMAIN+"/v3/users/login",
+ form: {
+ handleOrEmail: handleOrEmail,
+ password: password
+ }
+ //for more options check: https://github.com/mikeal/request#requestoptions-callback
+ }, function (err, response, body) {
+ console.log("response..............", err,response.statusCode);
+ if (err) return callback(err);
+ if (response.statusCode === 401) return callback();
+ var user = JSON.parse(body);
+ user.result.content.roles = user.result.content.roles.map(function(role) {
+ return role.roleName;
+ });
+
+ callback(null, {
+ user_id: user.result.content.id,
+ nickname: user.result.content.handle,
+ email: user.result.content.email,
+ handle:user.result.content.handle,
+ roles: user.result.content.roles,
+ email_verified: user.result.content.emailActive,
+ created_at: user.result.content.createdAt
+ });
+ });
+ }
+
\ No newline at end of file
diff --git a/web-assets/auth0/dev-tenant/rules/custom.js b/web-assets/auth0/dev-tenant/rules/custom.js
new file mode 100644
index 0000000..899cf76
--- /dev/null
+++ b/web-assets/auth0/dev-tenant/rules/custom.js
@@ -0,0 +1,78 @@
+
+function (user, context, callback) {
+ if (context.clientID === configuration.CLIENT_ACCOUNTS_LOGIN) { //
+ const _ = require('lodash');
+
+ // TODO: implement your rule
+ // if (context.protocol === "redirect-callback") {
+ // User was redirected to the /continue endpoint
+ if (context.redirect) {
+ return callback(null, user, context);
+ // returnning from here no need to check further
+ }
+ // otherwise to nothing
+
+ console.log("Enter Rule: Custom-Claims");
+ let handle = _.get(user, "handle", null);
+ const provider = _.get(user, "identities[0].provider", null);
+ if (!handle && provider === "auth0") {
+ handle = _.get(user, "nickname", null);
+ }
+ console.log("Fetch roles for email/handle: ", user.email, handle, provider);
+
+ global.AUTH0_CLAIM_NAMESPACE = "https://" + configuration.DOMAIN + "/";
+ try {
+ request.post({
+ url: 'https://api.' + configuration.DOMAIN + '/v3/users/roles',
+ form: {
+ email: user.email,
+ handle: handle
+ }
+ }, function (err, response, body) {
+ console.log("called topcoder api for role: response status - ", response.statusCode);
+ if (err) return callback(err, user, context);
+ if (response.statusCode !== 200) {
+ return callback('Login Error: Whoops! Something went wrong. Looks like your registered email has discrepancy with Authentication. Please connect to our support support@topcoder.com. Back to application ', user, context);
+ }
+
+ let res = JSON.parse(body);
+ // TODO need to double sure about multiple result or no result
+ let userId = res.result.content.id;
+ let handle = res.result.content.handle;
+ let roles = res.result.content.roles.map(function (role) {
+ return role.roleName;
+ });
+ let userStatus = res.result.content.active; // true/false
+
+ // TEMP
+ let tcsso = res.result.content.regSource || '';
+
+ context.idToken[global.AUTH0_CLAIM_NAMESPACE + 'roles'] = roles;
+ context.idToken[global.AUTH0_CLAIM_NAMESPACE + 'userId'] = userId;
+ context.idToken[global.AUTH0_CLAIM_NAMESPACE + 'handle'] = handle;
+ context.idToken[global.AUTH0_CLAIM_NAMESPACE + 'user_id'] = user.identities[0].provider + "|" + userId;
+ context.idToken[global.AUTH0_CLAIM_NAMESPACE + 'tcsso'] = tcsso;
+ context.idToken[global.AUTH0_CLAIM_NAMESPACE + 'active'] = userStatus;
+ context.idToken.nickname = handle;
+ //console.log(user, context);
+ if (!userStatus) {
+ context.redirect = {
+ url: `https://accounts-auth0.${configuration.DOMAIN}/check_email.html`
+ };
+ return callback(null, user, context);
+ }
+ if (!userStatus && context.login_counts > 1) {
+ return callback('Login Alert: Please verify your email first! Please connect to our support support@topcoder.com. Back to application ', user, context);
+ }
+ return callback(null, user, context);
+ }
+ );
+ } catch (e) {
+ console.log("Error in calling user roles" + e);
+ return callback("Something went worng!. Please retry.", user, context);
+ }
+ } else {
+ // for other apps do nothing
+ return callback(null, user, context);
+ }
+}
\ No newline at end of file
diff --git a/web-assets/auth0/dev-tenant/rules/enterprise.js b/web-assets/auth0/dev-tenant/rules/enterprise.js
new file mode 100644
index 0000000..cc31fe1
--- /dev/null
+++ b/web-assets/auth0/dev-tenant/rules/enterprise.js
@@ -0,0 +1,163 @@
+
+function (user, context, callback) {
+ if (context.clientID === configuration.CLIENT_ACCOUNTS_LOGIN) { // client/application specific
+
+ const _ = require('lodash');
+ console.log("Enter Rule: Enterprise-User-Registration");
+
+ const baseApiUrl = "https://api." + configuration.DOMAIN + "/v3";
+ //console.log("register user rule executed- user", user);
+ //console.log("register user rule executed - context", context);
+
+ const isEnterprise = (_.get(user, "identities[0].provider") !== 'auth0') &&
+ !(_.get(user, "identities[0].isSocial")) ? true : false;
+
+ console.log("Is enterprise login: ", isEnterprise);
+ if (isEnterprise) {
+ let provider = _.get(user, "identities[0].connection");
+ const providerType = _.get(user, "identities[0].provider");
+ let userId = _.get(user, "identities[0].user_id");
+ userId = userId.substring(userId.lastIndexOf('|') + 1);
+
+ let handle = _.get(user, "nickname", "");
+ const lastName = _.get(user, "family_name");
+ const firstName = _.get(user, "given_name");
+ const email = _.get(user, "email");
+ //const emailVerified = _.get(user, "email_verified", true);
+ const name = _.get(user, "name");
+
+ let isoAlpha2Code = _.get(context, "request.geoip.country_code");
+ let isoAlpha3Code = _.get(context, "request.geoip.country_code3");
+ let countryCode = _.get(context, "request.geoip.country_name");
+ let regSource = _.get(context, "request.query.regSource", null);
+ let retUrl = _.get(context, "request.query.returnUrl", null);
+ let utmSource = _.get(context, "request.query.utmSource", null);
+ let utmMedium = _.get(context, "request.query.utmMedium", null);
+ let utmCampaign = _.get(context, "request.query.utmCampaign", null);
+
+ const resourcePath = '/identityproviders?filter=handle=' + email;
+ const afterActivationURL = configuration.DEFAULT_AFTER_ACTIVATION_URL;
+ const hostName = _.get(context, "request.hostname", null);
+ const registrationCompletetUrl = "https://" + hostName + "/continue";
+ //const userHandleRedirectUrl = configuration.CUSTOM_PAGES_BASE_URL + '/signup.html?source='+ utmSource + '&formAction=' + registrationCompletetUrl;
+ const userHandleRedirectUrl = configuration.CUSTOM_PAGES_BASE_URL +
+ "/signup.html?regSource=" + regSource +
+ "&firstName=" + encodeURIComponent(firstName) +
+ "&lastName=" + encodeURIComponent(lastName) +
+ "&utmSource=" + encodeURIComponent(utmSource) +
+ "&utmMedium=" + encodeURIComponent(utmMedium) +
+ "&utmCampaign=" + encodeURIComponent(utmCampaign) +
+ "&formAction=" + registrationCompletetUrl +
+ "&returnUrl=" + retUrl;
+
+ console.log("provider", provider, email);
+ try {
+ request.get({
+ url: baseApiUrl + resourcePath
+ }, function (err, response, body) {
+ console.log("Enterprise user check - responseBody", body);
+
+ if (err) {
+ console.log("Enterprise validation error:", err);
+ }
+
+ /**
+ * check if enterprise profile is valid for our TC database
+ */
+
+ /*
+ Aug 2021 adding new wipro-sso connection with name wipro_azuread
+ */
+
+ if (_.includes([configuration.WIPRO_SSO_AZURE_AD_CONNECTION_NAME], provider)
+ ) {
+ provider = configuration.WIPRO_SSO_ADFS_CONNECTION_NAME;
+ }
+
+ let isSSOUserExist = (_.get(JSON.parse(body), "result.content.name") === provider) ?
+ true : false;
+
+ console.log("Enterprise customer alreday available:", isSSOUserExist);
+ if (!isSSOUserExist) {
+ console.log("register enterprise user.");
+ if (context.protocol === "redirect-callback") {
+ // User was redirected to the /continue endpoint
+ console.log("print data", typeof context);
+ console.log("get user extra data from query param");
+ handle = _.get(context, "request.query.handle", handle);
+ console.log("...Handle....", handle);
+
+ const countryStr = _.get(context, "request.query.country", null);
+ const countryObj = JSON.parse(countryStr);
+ if (countryObj) {
+ countryCode = _.get(countryObj, "code", countryCode);
+ isoAlpha2Code = _.get(countryObj, "alpha2", isoAlpha2Code);
+ isoAlpha3Code = _.get(countryObj, "alpha3", isoAlpha3Code);
+ }
+ utmSource = _.get(context, "request.query.source", utmSource);
+ utmMedium = _.get(context, "request.query.utmMedium", utmMedium);
+ utmCampaign = _.get(context, "request.query.utmCampaign", utmCampaign);
+ } else {
+ console.log('Redirect to choose user handle page.');
+ context.redirect = {
+ url: userHandleRedirectUrl
+ };
+ return callback(null, user, context);
+ }
+ // Enterprise profile will be active default
+ let data = {
+ "param": {
+ "handle": handle,
+ "firstName": firstName,
+ "lastName": lastName,
+ "email": email,
+ "country": {
+ "code": countryCode,
+ "isoAlpha3Code": isoAlpha3Code,
+ "isoAlpha2Code": isoAlpha2Code
+ },
+ "utmSource": utmSource,
+ "utmMedium": utmMedium,
+ "utmCampaign": utmCampaign,
+ "active": true,
+ "profile": {
+ "name": name,
+ "email": email,
+ "providerType": providerType,
+ "provider": provider,
+ "userId": userId
+ }
+ },
+ "options": {
+ "afterActivationURL": encodeURIComponent( configuration.DEFAULT_AFTER_ACTIVATION_URL)
+ }
+ };
+ console.log("Going to add enterprise", JSON.stringify(data));
+ request.post({
+ url: "https://api." + configuration.DOMAIN + "/v3/users",
+ json: data
+ }, function (error, response, body) {
+ if (response.statusCode !== 200) {
+ console.log("Enterprise registration error", error);
+ }
+ // on success
+ return callback(null, user, context);
+ //if (response.statusCode === 401) return callback();
+ });
+ } else { // valid social user if block end
+ return callback(null, user, context);
+ }
+ }
+ ); // end validatesocial request
+ } catch (e) {
+ console.log(`Error in calling validate enterprise user ${e}`);
+ return callback(null, user, context);
+ }
+ } else {// end isSocial if-block
+ console.log("existing from Enterprise-User-Registration rule.");
+ return callback(null, user, context);
+ }
+ } else { // END client-id check
+ return callback(null, user, context);
+ }
+}
diff --git a/web-assets/auth0/dev-tenant/rules/onboardingChecklist.js b/web-assets/auth0/dev-tenant/rules/onboardingChecklist.js
new file mode 100644
index 0000000..a443ceb
--- /dev/null
+++ b/web-assets/auth0/dev-tenant/rules/onboardingChecklist.js
@@ -0,0 +1,145 @@
+function (user, context, callback) {
+ if (context.clientID === configuration.CLIENT_ACCOUNTS_LOGIN) {
+ console.log("rule:onboarding-checklist:enter");
+ console.log("rule:onboarding-checklist:context.request", context.request);
+
+ if (context.redirect) {
+ console.log("rule:onboarding-checklist:exiting due to context being a redirect");
+ return callback(null, user, context);
+ }
+
+ const _ = require('lodash');
+ const moment = require('moment');
+
+ let handle = _.get(user, "handle", null);
+ const provider = _.get(user, "identities[0].provider", null);
+ if (!handle && provider === "auth0") {
+ handle = _.get(user, "nickname", null);
+ }
+
+ console.log("rule:onboarding-checklist: fetch onboarding_checklist for email/handle: ", user.email, handle, provider);
+
+ const createdAt = _.get(user, "created_at", null);
+ const thresholdDate = moment(configuration.PROFILE_CREATION_DATE_THRESHOLD, "YYYY-MM-DD");
+
+ try {
+ // 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.");
+ return callback(null, user, context);
+ }
+ } 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) {
+ if (global.M2MToken) {
+ 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...');
+ return callback(null, global.M2MToken);
+ }
+ }
+
+ console.log('rule:onboarding-checklist:Fetching new M2M token');
+ request.post({
+ url: `https://auth0proxy.${configuration.DOMAIN}/token`,
+ headers: 'content-type: application/json',
+ json: {
+ client_id: configuration.M2M_CLIENT_ID,
+ client_secret: configuration.M2M_CLIENT_SECRET,
+ audience: configuration.M2M_AUDIENCE,
+ auth0_url: configuration.M2M_TOKEN_URL,
+ grant_type: 'client_credentials'
+ }
+ }, function (err, response, body) {
+ if (err) {
+ return callback(err);
+ }
+
+ global.M2MToken = body.access_token;
+ 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.');
+ return callback(null, user, context);
+ }
+ global.AUTH0_CLAIM_NAMESPACE = "https://" + configuration.DOMAIN + "/";
+ const axios = require('axios@0.19.2');
+
+ 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 + 'show_onboarding_wizard'] = true;
+ console.log('rule:onboarding-checklist:Setting show_onboarding_wizard to true', user);
+ return callback(null, user, context);
+ }
+
+ const onboardingChecklistTrait = data.filter((item) => item.traitId === 'onboarding_checklist')[0].traits;
+
+ for (let checklistTrait of onboardingChecklistTrait.data) {
+ if (
+ checklistTrait.onboarding_wizard != null &&
+ (checklistTrait.onboarding_wizard.status != null || // any valid status indicates user has already seen onboarding wizard and needn't be shown again.
+ checklistTrait.onboarding_wizard.skip) // for certain signup routes skip is set to true, and thus onboarding wizard needn't be shown
+ ) {
+ return callback(null, user, context);
+ }
+ }
+
+ const profileCompletedData = onboardingChecklistTrait.data[0].profile_completed;
+
+ 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 show_onboarding_wizard', user);
+ context.idToken[global.AUTH0_CLAIM_NAMESPACE + 'show_onboarding_wizard'] = true;
+ 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);
+ }
+}
diff --git a/web-assets/auth0/dev-tenant/rules/resendEmail.js b/web-assets/auth0/dev-tenant/rules/resendEmail.js
new file mode 100644
index 0000000..02cc09a
--- /dev/null
+++ b/web-assets/auth0/dev-tenant/rules/resendEmail.js
@@ -0,0 +1,49 @@
+
+function (user, context, callback) {
+ if (context.clientID === configuration.CLIENT_ACCOUNTS_LOGIN) { // client/application specific
+ // TODO: implement your rule
+ const _ = require('lodash');
+
+ const resend = _.get(context, "request.query.resend", null);
+
+ if (context.protocol === 'redirect-callback' && resend) {
+ console.log("----------:Entered Email Resend Rule:------------");
+ let handle = _.get(user, "handle", null);
+ const provider = _.get(user, "identities[0].provider", null);
+ if (!handle && provider === "auth0") {
+ handle = _.get(user, "nickname", null);
+ }
+
+ global.AUTH0_CLAIM_NAMESPACE = "https://" + configuration.DOMAIN + "/";
+ // trigger resend email event at identity servcie
+ try {
+ request.post({
+ url: 'https://api.' + configuration.DOMAIN + '/v3/users/resendEmail',
+ form: {
+ email: user.email,
+ handle: handle
+ }
+ }, function (err, response, body) {
+ console.log("called topcoder api for resend email: response status - ", response.statusCode);
+ if (err) return callback(err, user, context);
+ if (response.statusCode !== 200) {
+ //{"id":"2fb48e50:17a334870b1:-457c","result":{"success":true,"status":400,"metadata":null,"content":"User has been activated"},"version":"v3"}
+
+ const error_message = _.get(JSON.parse(body), 'result.content', 'unknown error');
+ return callback(`Resend email error: ${error_message}`, user, context);
+ }
+ return callback(null, user, context);
+ }
+ );
+ } catch (e) {
+ return callback("Something went worng!. Please retry.", user, context);
+ }
+ // returnning from here no need to check further
+ } else { // if it is not redirect, do nothing
+ return callback(null, user, context);
+ }
+ } else {
+ // for other apps do nothing
+ return callback(null, user, context);
+ }
+}
\ No newline at end of file
diff --git a/web-assets/auth0/dev-tenant/rules/social.js b/web-assets/auth0/dev-tenant/rules/social.js
new file mode 100644
index 0000000..afdfb83
--- /dev/null
+++ b/web-assets/auth0/dev-tenant/rules/social.js
@@ -0,0 +1,183 @@
+
+function (user, context, callback) {
+ if (context.clientID === configuration.CLIENT_ACCOUNTS_LOGIN) { // client/application specific
+ global.AUTH0_CLAIM_NAMESPACE = "https://" + configuration.DOMAIN + "/";
+ const _ = require('lodash');
+ console.log("Enter Rule: Social-User-Registration");
+ const isSocial = _.get(user, "identities[0].isSocial");
+ const connection = _.get(user, "identities[0].connection");
+ console.log("is social login", isSocial);
+ if (isSocial) {
+ let provider = _.get(user, "identities[0].provider");
+ let userId = _.get(user, "identities[0].user_id");
+ // changes for github custom setup
+ if (connection.includes('github')) {
+ provider = 'github';
+ if (typeof userId === 'string' || userId instanceof String) {
+ let resArray = userId.split('|');
+ userId = resArray[1];
+ }
+ }
+
+ const accessToken = _.get(user, "identities[0].access_token");
+ const email = _.get(user, "email");
+ const emailVerified = _.get(user, "email_verified");
+ const name = _.get(user, "name");
+ const auth0UserId = _.get(user, "user_id");
+ const hostName = _.get(context, "request.hostname", null);
+ const registrationCompletetUrl = "https://" + hostName + "/continue";
+
+ let handle = _.get(user, "nickname", null);
+ let lastName = _.get(user, "family_name");
+ let firstName = _.get(user, "given_name");
+ let isoAlpha2Code = _.get(context, "request.geoip.country_code");
+ let isoAlpha3Code = _.get(context, "request.geoip.country_code3");
+ let countryCode = _.get(context, "request.geoip.country_name");
+ let regSource = _.get(context, "request.query.regSource", null);
+ let utmSource = _.get(context, "request.query.utmSource", null);
+ let utmMedium = _.get(context, "request.query.utmMedium", null);
+ let utmCampaign = _.get(context, "request.query.utmCampaign", null);
+ let retUrl = _.get(context, "request.query.returnUrl", null);
+
+ //console.log("resource", regSource, _.get(context, "request.query"));
+
+ const userHandleRedirectUrl = configuration.CUSTOM_PAGES_BASE_URL +
+ "/signup.html?regSource=" + regSource +
+ "&firstName=" + encodeURIComponent(firstName) +
+ "&lastName=" + encodeURIComponent(lastName) +
+ "&utmSource=" + encodeURIComponent(utmSource) +
+ "&utmMedium=" + encodeURIComponent(utmMedium) +
+ "&utmCampaign=" + encodeURIComponent(utmCampaign) +
+ "&formAction=" + registrationCompletetUrl +
+ "&returnUrl=" + retUrl;
+
+ const baseApiUrl = "https://api." + configuration.DOMAIN + "/v3/users";
+ const resourcePath = '/validateSocial?socialUserId=' + userId + '&socialProvider=' + provider;
+ let afterActivationURL = configuration.DEFAULT_AFTER_ACTIVATION_URL;
+
+ console.log("provider", provider);
+ try {
+ request.get({
+ url: baseApiUrl + resourcePath
+ }, function (err, response, body) {
+ //console.log("social user check - responseBody", body);
+
+ if (err) {
+ console.log("Social validation error:", err);
+ }
+
+ /**
+ * check if social profile is valid for our TC database
+ */
+ let flag = _.get(JSON.parse(body), "result.content.valid");
+ console.log("Is valid social profile: ", flag, response.statusCode);
+ if (response.statusCode !== 200) {
+ console.log(`Error in calling validate social user: ${body}`);
+ return callback(null, user, context);
+ }
+ if (flag) {
+ console.log("register social login");
+ if (context.protocol === "redirect-callback") {
+ // User was redirected to the /continue endpoint
+ console.log("get user extra data from query param");
+ handle = _.get(context, "request.query.handle", handle);
+ const countryStr = _.get(context, "request.query.country", null);
+ const countryObj = JSON.parse(countryStr);
+ if (countryObj) {
+ countryCode = _.get(countryObj, "code", countryCode);
+ isoAlpha2Code = _.get(countryObj, "alpha2", isoAlpha2Code);
+ isoAlpha3Code = _.get(countryObj, "alpha3", isoAlpha3Code);
+ }
+ regSource = _.get(context, "request.query.source", regSource);
+ firstName = _.get(context, "request.query.firstName", firstName);
+ lastName = _.get(context, "request.query.lastName", lastName);
+ utmSource = _.get(context, "request.query.source", utmSource);
+ utmMedium = _.get(context, "request.query.utmMedium", utmMedium);
+ utmCampaign = _.get(context, "request.query.utmCampaign", utmCampaign);
+ retUrl = _.get(context, "request.query.returnUrl", retUrl);
+ console.log("------HHHHHH-----", context.request);
+ afterActivationURL = retUrl ? retUrl : afterActivationURL;
+ if (regSource === configuration.REG_BUSINESS) {
+ afterActivationURL = "https://connect." + configuration.DOMAIN;
+ }
+ // workaround: to avoid activation email failure
+ if (!firstName) {
+ firstName = _.get(user, "nickname", firstName);
+ }
+ if (!lastName) {
+ lastName = _.get(user, "nickname", lastName);
+ }
+ // end workaround
+
+ const data = {
+ "param": {
+ "handle": handle,
+ "firstName": firstName,
+ "lastName": lastName,
+ "email": email,
+ "country": {
+ "code": countryCode,
+ "isoAlpha3Code": isoAlpha3Code,
+ "isoAlpha2Code": isoAlpha2Code
+ },
+ "utmSource": utmSource,
+ "utmMedium": utmMedium,
+ "utmCampaign": utmCampaign,
+ "regSource": regSource,
+ "profile": {
+ "userId": userId,
+ "name": name,
+ "providerType": provider,
+ "email": email,
+ "emailVerified": emailVerified,
+ "context": {
+ "handle": handle,
+ "accessToken": accessToken,
+ "auth0UserId": auth0UserId
+ }
+ }
+ },
+ "options": {
+ "afterActivationURL": encodeURIComponent( configuration.DEFAULT_AFTER_ACTIVATION_URL)
+ }
+ };
+ request.post({
+ url: "https://api." + configuration.DOMAIN + "/v3/users",
+ json: data
+ }, function (error, response, body) {
+ if (response.statusCode !== 200) {
+ console.log("------- Social registration error occurred -------Http error status:", response.statusCode);
+ console.log("Error message:", body.result.content);
+ return callback( "Social Registration Error: " + body.result.content + " Please retry.", user, context);
+ }
+ // on success
+ return callback(null, user, context);
+ });
+ } else {
+ console.log('Redirect to choose user handle page.', provider);
+ if (provider === "giveprovider") {
+ return callback("Github signup is temporarily disabled. You can signup directly using a username / password or another social signup.", user, context);
+ } else {
+ context.redirect = {
+ url: userHandleRedirectUrl
+ };
+ return callback(null, user, context);
+ }
+ }
+ } else { // valid social user if block end
+ return callback(null, user, context);
+ }
+ }
+ ); // end validatesocial request
+ } catch (e) {
+ console.log(`Error in calling validate social user ${e}`);
+ return callback('Error in validating social user. Please rety.', user, context);
+ }
+ } else {// end isSocial if-block
+ console.log("existing from Social-User-Registration rule.");
+ return callback(null, user, context);
+ }
+ } else {
+ return callback(null, user, context);
+ }
+}
diff --git a/web-assets/auth0/dev-tenant/rules/user-privacy-policy.js b/web-assets/auth0/dev-tenant/rules/user-privacy-policy.js
new file mode 100644
index 0000000..f4130c4
--- /dev/null
+++ b/web-assets/auth0/dev-tenant/rules/user-privacy-policy.js
@@ -0,0 +1,107 @@
+function (user, context, callback) {
+ if (context.clientID === configuration.CLIENT_ACCOUNTS_LOGIN) { // client/application specific
+ console.log("rule:user-privacy-policy:enter");
+
+ const _ = require('lodash');
+
+ const loginCount = _.get(context, "stats.loginsCount");
+ const isAuth0 = (_.get(user, "identities[0].provider") === 'auth0') ? true : false;
+
+ /**
+ * Note : Sachin Maheshwari
+ * This rule should be execute after Custom-Claims Rule,
+ * to get the userId for social and enterprise login in 'IdToken'
+ */
+ var userId = _.get(context, `idToken['https://${configuration.DOMAIN}/userId']`, null);
+
+ if (isAuth0) {
+ // no need to check futher as this rule is other than Auth0 i.e. social or enterprise
+ //return callback(null, user, context);
+ userId = _.get(user, "identities[0].user_id", null);
+ }
+
+ console.log('rule:user-privacy-policy:logincount', loginCount);
+ console.log('rule:user-privacy-policy:userId', userId);
+
+ if (!userId) {
+ // no need to check futher
+ console.log('rule:user-privacy-policy:error:user_id null');
+ return callback(null, user, context);
+ }
+
+ if (loginCount < 3) {
+ const getToken = function (tokenCB) {
+ if (global.M2MToken) {
+ console.log('rule:user-privacy-policy:a M2M token is present');
+ const jwt = require('jsonwebtoken');
+ const moment = require('moment');
+ const decoded = jwt.decode(global.M2MToken);
+ const exp = moment.unix(decoded.exp);
+
+ if (exp > new Date()) {
+ console.log('M2MToken is still valid. reusing token');
+ tokenCB(null, global.M2MToken);
+ return;
+ }
+ }
+ console.log('rule:user-privacy-policy:fetching fresh m2m token');
+ request.post({
+ url: `https://auth0proxy.${configuration.DOMAIN}/token`,
+ headers: 'content-type: application/json',
+ json: {
+ client_id: configuration.M2M_CLIENT_ID,
+ client_secret: configuration.M2M_CLIENT_SECRET,
+ audience: configuration.M2M_AUDIENCE,
+ auth0_url: configuration.M2M_TOKEN_URL,
+ grant_type: 'client_credentials'
+ }
+ }, function (err, response, body) {
+ if (err) {
+ tokenCB(err);
+ return;
+ }
+
+ global.M2MToken = body.access_token;
+ console.log('rule:user-privacy-policy:setting the M2MToken globally');
+ tokenCB(null, global.M2MToken);
+ });
+ };
+
+ const callTermApi = function (token) {
+ console.log("rule:user-privacy-policy:calling Term API");
+
+ var payload = { userId };
+
+ request.post({
+ url: `https://api.${configuration.DOMAIN}/v5/terms/${configuration.TERMS_USER_PRIVACY_POLICY_UUID}/users`,
+ headers: {
+ 'Authorization': 'Bearer ' + token,
+ 'Content-Type': 'application/json'
+ },
+ json: payload
+ },
+ function (err, response, body) {
+ // swallow error
+ if (err) {
+ //console.log(err);
+ } else {
+ console.log('rule:user-privacy-policy:called term API!');
+ console.log('rule:user-privacy-policy:response - ', body);
+ }
+ callback(null, user, context);
+ });
+ };
+
+ getToken(function (err, token) {
+ if (err) {
+ console.log(err);
+ } else {
+ console.log('rule:user-privacy-policy:m2m token', token);
+ callTermApi(token);
+ }
+ });
+ } // if login count
+
+ } // if end
+ return callback(null, user, context);
+}
diff --git a/web-assets/js/setupAuth0WithRedirect.js b/web-assets/js/setupAuth0WithRedirect.js
index 8b3aaf7..5e0d233 100644
--- a/web-assets/js/setupAuth0WithRedirect.js
+++ b/web-assets/js/setupAuth0WithRedirect.js
@@ -24,6 +24,8 @@ const qs = (function (a) {
const authSetup = function () {
let domain = 'auth.{{DOMAIN}}';
+
+ const onboardingWizardUrl = 'https://platform.{{DOMAIN}}/onboard';
const clientId = '{{AUTH0_CLIENT_ID}}';
const useLocalStorage = false;
const useRefreshTokens = false;
@@ -229,6 +231,11 @@ const authSetup = function () {
return token ? !isTokenExpired(token) : false;
};
+ const redirectToOnboardingWizard = function () {
+ logger("redirect to onboarding wizard");
+ window.location = onboardingWizardUrl;
+ }
+
const redirectToApp = function () {
logger("redirect to app", appUrl);
if (appUrl) {
@@ -258,6 +265,21 @@ const authSetup = function () {
const storeToken = function () {
auth0.getIdTokenClaims().then(function (claims) {
idToken = claims.__raw;
+
+ logger('Claims', JSON.stringify(claims));
+
+ let showOnboardingWizard = false;
+ Object.keys(claims).forEach(key => {
+ logger('Checking key', key);
+ if (key.indexOf('show_onboarding_wizard') !== -1) {
+ if (claims[key]) {
+ showOnboardingWizard = true;
+ }
+ }
+ });
+
+ logger('Show Onboarding Wizard', showOnboardingWizard);
+
let userActive = false;
Object.keys(claims).findIndex(function (key) {
if (key.includes('active')) {
@@ -265,7 +287,7 @@ const authSetup = function () {
return true;
}
return false;
- });
+ });
if (userActive) {
let tcsso = '';
Object.keys(claims).findIndex(function (key) {
@@ -291,11 +313,16 @@ const authSetup = function () {
logger('Error occured in fecthing token expiry time', e.message);
}
- // session still active, but app calling login
- if (!appUrl && returnAppUrl) {
- appUrl = returnAppUrl
+ if (showOnboardingWizard) {
+ logger('Take user to onboarding wizard');
+ redirectToOnboardingWizard();
+ } else {
+ // session still active, but app calling login
+ if (!appUrl && returnAppUrl) {
+ appUrl = returnAppUrl
+ }
+ redirectToApp();
}
- redirectToApp();
} else {
logger("User active ? ", userActive);
host = registerSuccessUrl;