diff --git a/build b/build
index 264b9fd4..b556ee57 100755
--- a/build
+++ b/build
@@ -36,6 +36,12 @@ async.reduce(files, [], (rules, file, callback) => {
const code = data.split('\n').slice(parsed.comment.end).join('\n').trim();
if (argv.allRules || parsed.gallery === 'true') {
+ const ruleDescription = converter.makeHtml(parsed.example);
+
+ if (!ruleDescription) {
+ return callback(new Error(`Blank description for ${parsed.title}`));
+ }
+
const rule = {
id: path.basename(file).replace('.js', ''),
title: parsed.title,
diff --git a/package-lock.json b/package-lock.json
index d5e915eb..9bceb7b8 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -1,6 +1,6 @@
{
"name": "rules-templates",
- "version": "0.18.0",
+ "version": "0.19.0",
"lockfileVersion": 1,
"requires": true,
"dependencies": {
diff --git a/package.json b/package.json
index cc9f56c7..e5345cc7 100644
--- a/package.json
+++ b/package.json
@@ -1,6 +1,6 @@
{
"name": "rules-templates",
- "version": "0.18.0",
+ "version": "0.19.0",
"description": "Auth0 Rules Repository",
"main": "./rules",
"scripts": {
diff --git a/rules.json b/rules.json
index 303699c9..17d20f72 100644
--- a/rules.json
+++ b/rules.json
@@ -471,6 +471,16 @@
{
"name": "marketplace",
"templates": [
+ {
+ "id": "arengu-policy-acceptance",
+ "title": "Arengu Policy Acceptance",
+ "overview": "Require your users to accept custom privacy policies or new terms.",
+ "categories": [
+ "marketplace"
+ ],
+ "description": "
Please see the Aregnu Policy Acceptance integration for more information and detailed installation instructions.
\nRequired configuration (this Rule will be skipped if any of the below are not defined):
\n\nSESSION_TOKEN_SECRET
: A long, random string at least 32 bytes long \nARENGU_POLICIES_FORM_URL
: The URL that contains an embedded form or with a hosted form page \n
",
+ "code": "async function arenguCheckUserPolicies(user, context, callback) {\n if (\n !configuration.SESSION_TOKEN_SECRET ||\n !configuration.ARENGU_POLICIES_FORM_URL\n ) {\n console.log('Missing required configuration. Skipping.');\n return callback(null, user, context);\n }\n\n const {\n Auth0RedirectRuleUtilities,\n Auth0UserUpdateUtilities\n } = require('@auth0/rule-utilities@0.2.0');\n\n const ruleUtils = new Auth0RedirectRuleUtilities(\n user,\n context,\n configuration\n );\n\n const userUtils = new Auth0UserUpdateUtilities(user, auth0);\n\n function mustAcceptNewPolicies() {\n // Use .getAppMeta() or .getUserMeta() as appropriate and modify the property key and value to your needs.\n return userUtils.getAppMeta('terms_accepted') !== true;\n }\n\n function validateSessionToken() {\n try {\n return ruleUtils.validateSessionToken();\n } catch (error) {\n callback(error);\n }\n }\n\n if (ruleUtils.isRedirectCallback && ruleUtils.queryParams.session_token) {\n const decodedToken = validateSessionToken();\n const customClaims = decodedToken.other;\n\n for (const [key, value] of Object.entries(customClaims)) {\n // Use .setAppMeta() or .setUserMeta() as appropriate\n userUtils.setAppMeta(key, value);\n }\n\n try {\n // Use .updateAppMeta() or .updateUserMeta() as appropriate\n await userUtils.updateAppMeta();\n\n return callback(null, user, context);\n } catch (error) {\n return callback(error);\n }\n }\n\n if (mustAcceptNewPolicies()) {\n ruleUtils.doRedirect(configuration.ARENGU_POLICIES_FORM_URL);\n\n return callback(null, user, context);\n }\n\n return callback(null, user, context);\n}"
+ },
{
"id": "arengu-progressive-profiling",
"title": "Arengu Progressive Profiling",
@@ -478,6 +488,7 @@
"categories": [
"marketplace"
],
+ "description": "Please see the Aregnu Progressive Profiling integration for more information and detailed installation instructions.
\nRequired configuration (this Rule will be skipped if any of the below are not defined):
\n\nSESSION_TOKEN_SECRET
: A long, random string at least 32 bytes long \nARENGU_PROFILE_FORM_URL
: The URL that contains an embedded form or with a hosted form page \n
",
"code": "async function arenguCompleteUserProfile(user, context, callback) {\n if (\n !configuration.SESSION_TOKEN_SECRET ||\n !configuration.ARENGU_PROFILE_FORM_URL\n ) {\n console.log('Missing required configuration. Skipping.');\n return callback(null, user, context);\n }\n\n const {\n Auth0RedirectRuleUtilities,\n Auth0UserUpdateUtilities\n } = require('@auth0/rule-utilities@0.2.0');\n\n const ruleUtils = new Auth0RedirectRuleUtilities(\n user,\n context,\n configuration\n );\n\n const userUtils = new Auth0UserUpdateUtilities(user, auth0);\n\n function validateSessionToken() {\n try {\n return ruleUtils.validateSessionToken();\n } catch (error) {\n callback(error);\n }\n }\n\n // Modify your login criteria to your needs\n function isLogin() {\n const loginCount = configuration.ARENGU_PROFILE_LOGIN_COUNT || 2;\n return context.stats.loginsCount > parseInt(loginCount, 10);\n }\n\n function isEmptyUserMeta(key) {\n return (\n userUtils.getUserMeta(key) === undefined ||\n userUtils.getUserMeta(key) === null ||\n userUtils.getUserMeta(key).length === 0\n );\n }\n\n function isProfileIncomplete() {\n // Add your required user_medata keys\n return isEmptyUserMeta('job_title') || isEmptyUserMeta('company_name');\n }\n\n if (ruleUtils.isRedirectCallback && ruleUtils.queryParams.session_token) {\n const decodedToken = validateSessionToken();\n const customClaims = decodedToken.other;\n\n for (const [key, value] of Object.entries(customClaims)) {\n userUtils.setUserMeta(key, value);\n }\n\n try {\n await userUtils.updateUserMeta();\n\n return callback(null, user, context);\n } catch (error) {\n return callback(error);\n }\n }\n\n if (isLogin() && isProfileIncomplete()) {\n ruleUtils.doRedirect(configuration.ARENGU_PROFILE_FORM_URL);\n }\n\n return callback(null, user, context);\n}"
},
{
@@ -507,6 +518,7 @@
"categories": [
"marketplace"
],
+ "description": "Please see the Incognia Authentication integration for more information and detailed installation instructions.
\nRequired configuration (this Rule will be skipped if any of the below are not defined):
\n\n- INCOGNIACLIENTID: The client ID obtained from Incognia's dashboard (My Apps > API Credentials)
\n- INCOGNIACLIENTSECRET: The client secret obtained from Incognia's dashboard (My Apps > API Credentials)
\n
",
"code": "async function incogniaAuthenticationRule(user, context, callback) {\n const _ = require('lodash@4.17.19');\n\n const { IncogniaAPI } = require('@incognia/api@1.0.0');\n\n const { INCOGNIA_CLIENT_ID, INCOGNIA_CLIENT_SECRET } = configuration;\n\n if (!INCOGNIA_CLIENT_ID || !INCOGNIA_CLIENT_SECRET) {\n console.log('Missing required configuration. Skipping.');\n return callback(null, user, context);\n }\n\n const installationId = _.get(\n context,\n 'request.query.incognia_installation_id'\n );\n if (!installationId) {\n console.log('Missing installation_id. Skipping.');\n return callback(null, user, context);\n }\n\n const accountId = _.get(user, 'user_id');\n if (!accountId) {\n console.log('Missing user_id. Skipping.');\n return callback(null, user, context);\n }\n\n let incogniaAPI;\n if (global.incogniaAPI) {\n incogniaAPI = global.incogniaAPI;\n } else {\n incogniaAPI = new IncogniaAPI({\n clientId: INCOGNIA_CLIENT_ID,\n clientSecret: INCOGNIA_CLIENT_SECRET\n });\n global.incogniaAPI = incogniaAPI;\n }\n\n try {\n const loginAssessment = await incogniaAPI.registerLoginAssessment({\n installationId: installationId,\n accountId: accountId\n });\n\n // Incognia's risk assessment will be in a namespaced claim so it can be used in other rules\n // for skipping/prompting MFA or in the mobile app itself to decide whether the user should be\n // redirected to step-up auth for example.\n context.idToken['https://www.incognia.com/assessment'] =\n loginAssessment.riskAssessment;\n } catch (error) {\n console.log('Error calling Incognia API for a new login.');\n return callback(error);\n }\n\n return callback(null, user, context);\n}"
},
{
@@ -516,6 +528,7 @@
"categories": [
"marketplace"
],
+ "description": "Please see the Incognia Onboarding integration for more information and detailed installation instructions.
\nRequired configuration (this Rule will be skipped if any of the below are not defined):
\n\n- INCOGNIACLIENTID: The client ID obtained from Incognia's dashboard (My Apps > API Credentials)
\n- INCOGNIACLIENTSECRET: The client secret obtained from Incognia's dashboard (My Apps > API Credentials)
\n
",
"code": "async function incogniaOnboardingRule(user, context, callback) {\n const _ = require('lodash@4.17.19');\n\n const { IncogniaAPI } = require('@incognia/api@1.0.0');\n const { Auth0UserUpdateUtilities } = require('@auth0/rule-utilities@0.2.0');\n\n const {\n INCOGNIA_CLIENT_ID,\n INCOGNIA_CLIENT_SECRET,\n INCOGNIA_HOME_ADDRESS_PROP\n } = configuration;\n\n if (!INCOGNIA_CLIENT_ID || !INCOGNIA_CLIENT_SECRET) {\n console.log('Missing required configuration. Skipping.');\n return callback(null, user, context);\n }\n\n const installationId = _.get(\n context,\n 'request.query.incognia_installation_id'\n );\n if (!installationId) {\n console.log('Missing installation_id. Skipping.');\n return callback(null, user, context);\n }\n\n // User home address should be set using Auth0's Signup API for example. If the home address is\n // not in 'user_metadata.home_address', please specify the path of the field inside the user\n // object where the home address is through the INCOGNIA_HOME_ADDRESS_PROP configuration.\n const homeAddressProp =\n INCOGNIA_HOME_ADDRESS_PROP || 'user_metadata.home_address';\n const homeAddress = _.get(user, homeAddressProp);\n if (!homeAddress) {\n console.log('Missing user home address. Skipping.');\n return callback(null, user, context);\n }\n\n const userUtils = new Auth0UserUpdateUtilities(user, auth0, 'incognia');\n\n const status = userUtils.getAppMeta('status');\n // This rule was previously run and calculated the assessment successfully.\n if (status && status !== 'pending') {\n console.log(\n 'Assessment is already calculated or is unevaluable. Skipping.'\n );\n return callback(null, user, context);\n }\n\n let incogniaAPI;\n if (global.incogniaAPI) {\n incogniaAPI = global.incogniaAPI;\n } else {\n incogniaAPI = new IncogniaAPI({\n clientId: INCOGNIA_CLIENT_ID,\n clientSecret: INCOGNIA_CLIENT_SECRET\n });\n global.incogniaAPI = incogniaAPI;\n }\n\n let onboardingAssessment;\n const signupId = userUtils.getAppMeta('signup_id');\n // The rule was previously run, but Incognia could not assess the signup.\n if (signupId) {\n try {\n onboardingAssessment = await incogniaAPI.getOnboardingAssessment(\n signupId\n );\n } catch (error) {\n console.log('Error calling Incognia API for signup previously submitted');\n return callback(error);\n }\n // This is the first time the rule is being run with all necessary arguments.\n } else {\n try {\n onboardingAssessment = await incogniaAPI.registerOnboardingAssessment({\n installationId: installationId,\n addressLine: homeAddress\n });\n } catch (error) {\n console.log('Error calling Incognia API for new signup submission');\n return callback(error);\n }\n }\n\n /*\n * Updates the status in the metadata now that the assessment was calculated. If the new\n * assessment is valid, the status will go to evaluated and this rule won't be executed again.\n * If Incognia still doesn't know how to assess the signup, it will try to calculate it again up\n * to 48 hours after the first try.\n */\n const firstAssessmentAt = userUtils.getAppMeta('first_assessment_at');\n let newStatus;\n if (onboardingAssessment.riskAssessment !== 'unknown_risk') {\n newStatus = 'evaluated';\n } else if (!firstAssessmentAt) {\n newStatus = 'pending';\n } else {\n const firstAssessmentAge =\n Math.round(Date.now() / 1000) - firstAssessmentAt;\n // 48 hours limit.\n if (firstAssessmentAge > 172800) {\n newStatus = 'unevaluable';\n } else {\n newStatus = 'pending';\n }\n }\n\n const updatedMetadata = {\n status: newStatus,\n first_assessment_at: firstAssessmentAt || Math.round(Date.now() / 1000),\n signup_id: onboardingAssessment.id,\n assessment: onboardingAssessment\n };\n\n try {\n userUtils.setAppMeta('incognia', updatedMetadata);\n await userUtils.updateAppMeta();\n } catch (error) {\n console.log('Error calling Auth0 management API');\n return callback(error);\n }\n\n return callback(null, user, context);\n}"
},
{
diff --git a/src/arengu-policy-acceptance.js b/src/rules/arengu-policy-acceptance.js
similarity index 74%
rename from src/arengu-policy-acceptance.js
rename to src/rules/arengu-policy-acceptance.js
index f4770df4..2202efe9 100644
--- a/src/arengu-policy-acceptance.js
+++ b/src/rules/arengu-policy-acceptance.js
@@ -3,6 +3,14 @@
* @overview Require your users to accept custom privacy policies or new terms.
* @gallery true
* @category marketplace
+ *
+ * Please see the [Aregnu Policy Acceptance integration](https://marketplace.auth0.com/integrations/arengu-policy-acceptance) for more information and detailed installation instructions.
+ *
+ * **Required configuration** (this Rule will be skipped if any of the below are not defined):
+ *
+ * - `SESSION_TOKEN_SECRET`: A long, random string at least 32 bytes long
+ * - `ARENGU_POLICIES_FORM_URL`: The URL that contains an [embedded form](https://github.com/arengu/forms-js-sdk#embed-a-form) or with a [hosted form page](https://www.arengu.com/pages)
+ *
*/
async function arenguCheckUserPolicies(user, context, callback) {
@@ -17,7 +25,7 @@ async function arenguCheckUserPolicies(user, context, callback) {
const {
Auth0RedirectRuleUtilities,
Auth0UserUpdateUtilities
- } = require("@auth0/rule-utilities@0.2.0");
+ } = require('@auth0/rule-utilities@0.2.0');
const ruleUtils = new Auth0RedirectRuleUtilities(
user,
@@ -66,4 +74,4 @@ async function arenguCheckUserPolicies(user, context, callback) {
}
return callback(null, user, context);
-}
\ No newline at end of file
+}
diff --git a/src/rules/arengu-progressive-profiling.js b/src/rules/arengu-progressive-profiling.js
index df7fadca..02d62242 100644
--- a/src/rules/arengu-progressive-profiling.js
+++ b/src/rules/arengu-progressive-profiling.js
@@ -3,6 +3,14 @@
* @overview Capture new users' information in your authentication flows.
* @gallery true
* @category marketplace
+ *
+ * Please see the [Aregnu Progressive Profiling integration](https://marketplace.auth0.com/integrations/arengu-progressive-profiling) for more information and detailed installation instructions.
+ *
+ * **Required configuration** (this Rule will be skipped if any of the below are not defined):
+ *
+ * - `SESSION_TOKEN_SECRET`: A long, random string at least 32 bytes long
+ * - `ARENGU_PROFILE_FORM_URL`: The URL that contains an [embedded form](https://github.com/arengu/forms-js-sdk#embed-a-form) or with a [hosted form page](https://www.arengu.com/pages)
+ *
*/
async function arenguCompleteUserProfile(user, context, callback) {
diff --git a/src/rules/incognia-authentication.js b/src/rules/incognia-authentication.js
index c8559bd9..ca713016 100644
--- a/src/rules/incognia-authentication.js
+++ b/src/rules/incognia-authentication.js
@@ -4,7 +4,14 @@
* @gallery true
* @category marketplace
*
+ * Please see the [Incognia Authentication integration](https://marketplace.auth0.com/integrations/incognia-authentication) for more information and detailed installation instructions.
+ *
+ * **Required configuration** (this Rule will be skipped if any of the below are not defined):
+ *
+ * - INCOGNIA_CLIENT_ID: The client ID obtained from Incognia's dashboard (My Apps > API Credentials)
+ * - INCOGNIA_CLIENT_SECRET: The client secret obtained from Incognia's dashboard (My Apps > API Credentials)
*/
+
async function incogniaAuthenticationRule(user, context, callback) {
const _ = require('lodash@4.17.19');
diff --git a/src/rules/incognia-onboarding.js b/src/rules/incognia-onboarding.js
index fe45afa8..f2d50dde 100644
--- a/src/rules/incognia-onboarding.js
+++ b/src/rules/incognia-onboarding.js
@@ -4,7 +4,14 @@
* @gallery true
* @category marketplace
*
+ * Please see the [Incognia Onboarding integration](https://marketplace.auth0.com/integrations/incognia-onboarding) for more information and detailed installation instructions.
+ *
+ * **Required configuration** (this Rule will be skipped if any of the below are not defined):
+ *
+ * - INCOGNIA_CLIENT_ID: The client ID obtained from Incognia's dashboard (My Apps > API Credentials)
+ * - INCOGNIA_CLIENT_SECRET: The client secret obtained from Incognia's dashboard (My Apps > API Credentials)
*/
+
async function incogniaOnboardingRule(user, context, callback) {
const _ = require('lodash@4.17.19');