Skip to content

Commit

Permalink
Merge pull request #3095 from GoogleCloudPlatform/demosite-control-flow
Browse files Browse the repository at this point in the history
docs(demosite-recaptcha): update client to server control flow
  • Loading branch information
Sita04 authored Mar 29, 2023
2 parents dfb9bd6 + e58bf30 commit 39d8e05
Show file tree
Hide file tree
Showing 14 changed files with 472 additions and 211 deletions.
5 changes: 5 additions & 0 deletions recaptcha_enterprise/demosite/app/config.properties
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
recaptcha_action.home=home
recaptcha_action.login=log_in
recaptcha_action.signup=sign_up
recaptcha_action.store=check_out
recaptcha_action.comment=send_comment
290 changes: 265 additions & 25 deletions recaptcha_enterprise/demosite/app/controllers/controller.js
Original file line number Diff line number Diff line change
Expand Up @@ -12,65 +12,305 @@
// See the License for the specific language governing permissions and
// limitations under the License.

// Sample threshold score for classification of bad / not bad action. The threshold score
// can be used to trigger secondary actions like MFA.
const SAMPLE_THRESHOLD_SCORE = 0.5;
const BAD = 'Bad';
const NOT_BAD = 'Not Bad';

// Parse config file and read available reCAPTCHA actions. All reCAPTCHA actions registered in the client
// should be mapped in the config file. This will be used to verify if the token obtained during assessment
// corresponds to the claimed action.
const propertiesReader = require('properties-reader');
const PROPERTIES = propertiesReader('config.properties');

const context = {
project_id: process.env.GOOGLE_CLOUD_PROJECT,
site_key: process.env.SITE_KEY,
};

const homeController = (req, res) => {
// Return homepage template.
const home = (req, res) => {
res.render('home', context);
};

const storeController = (req, res) => {
res.render('store', context);
// Return signup template.
const signup = (req, res) => {
res.render('signup', context);
};

const loginController = (req, res) => {
// Return login template.
const login = (req, res) => {
res.render('login', context);
};

const commentController = (req, res) => {
res.render('comment', context);
// Return store template.
const store = (req, res) => {
res.render('store', context);
};

const signupController = (req, res) => {
res.render('signup', context);
// Return comment template.
const comment = (req, res) => {
res.render('comment', context);
};

const gameController = (req, res) => {
// Return game template.
const game = (req, res) => {
res.render('game', context);
};

const {createAssessment} = require('../recaptcha/createAssessment');
const assessmentController = async (req, res) => {
// On homepage load, execute reCAPTCHA Enterprise assessment and take action according to the score.
const onHomepageLoad = async (req, res) => {
try {
// <!-- ATTENTION: reCAPTCHA Example (Server Part 1/2) Starts -->
const assessmentData = await createAssessment(
process.env.GOOGLE_CLOUD_PROJECT,
const assessmentResponse = await createAssessment(
context.project_id,
context.site_key,
req.body.recaptcha_cred.token,
req.body.recaptcha_cred.action
req.body.recaptcha_cred.token
);

const verdict = function () {
// Check if the token is valid, score is above threshold score and the action equals expected.
if (
assessmentResponse.tokenProperties.valid &&
assessmentResponse.riskAnalysis.score > SAMPLE_THRESHOLD_SCORE &&
assessmentResponse.tokenProperties.action ===
PROPERTIES.get('recaptcha_action.home')
) {
// Load the home page.
// Business logic.
// Classify the action as not bad.
return NOT_BAD;
} else {
// If any of the above condition fails, trigger email/ phone verification flow.
// Classify the action as bad.
return BAD;
}
};
// <!-- ATTENTION: reCAPTCHA Example (Server Part 1/2) Ends -->

// Return the risk score.
const result = {
score: assessmentResponse.riskAnalysis.score.toFixed(1),
verdict: verdict(),
};
res.json({
data: result,
});
} catch (e) {
res.json({
data: {
error_msg: e,
},
});
}
};

// On signup button click, execute reCAPTCHA Enterprise assessment and take action according to the score.
const onSignup = async (req, res) => {
try {
// <!-- ATTENTION: reCAPTCHA Example (Server Part 1/2) Starts -->
const assessmentResponse = await createAssessment(
context.project_id,
context.site_key,
req.body.recaptcha_cred.token
);

const verdict = function () {
// Check if the token is valid, score is above threshold score and the action equals expected.
if (
assessmentResponse.tokenProperties.valid &&
assessmentResponse.riskAnalysis.score > SAMPLE_THRESHOLD_SCORE &&
assessmentResponse.tokenProperties.action ===
PROPERTIES.get('recaptcha_action.signup')
) {
// Write new username and password to users database.
// let username = req.body.recaptcha_cred.username
// let password = req.body.recaptcha_cred.password
// Business logic.
// Classify the action as not bad.
return NOT_BAD;
} else {
// If any of the above condition fails, trigger email/ phone verification flow.
// Classify the action as bad.
return BAD;
}
};
// <!-- ATTENTION: reCAPTCHA Example (Server Part 1/2) Ends -->

// Return the risk score.
const result = {
score: assessmentResponse.riskAnalysis.score.toFixed(1),
verdict: verdict(),
};
res.json({
data: result,
});
} catch (e) {
res.json({
data: {
error_msg: e,
},
});
}
};

// On login button click, execute reCAPTCHA Enterprise assessment and take action according to the score.
const onLogin = async (req, res) => {
try {
// <!-- ATTENTION: reCAPTCHA Example (Server Part 1/2) Starts -->
const assessmentResponse = await createAssessment(
context.project_id,
context.site_key,
req.body.recaptcha_cred.token
);

const verdict = function () {
// Check if the token is valid, score is above threshold score and the action equals expected.
if (
assessmentResponse.tokenProperties.valid &&
assessmentResponse.riskAnalysis.score > SAMPLE_THRESHOLD_SCORE &&
assessmentResponse.tokenProperties.action ===
PROPERTIES.get('recaptcha_action.login')
) {
// Check if the login credentials exist and match.
// let username = req.body.recaptcha_cred.username
// let password = req.body.recaptcha_cred.password
// Business logic.
// Classify the action as not bad.
return NOT_BAD;
} else {
// If any of the above condition fails, trigger email/ phone verification flow.
// Classify the action as bad.
return BAD;
}
};
// <!-- ATTENTION: reCAPTCHA Example (Server Part 1/2) Ends -->

// Return the risk score.
const result = {
score: assessmentResponse.riskAnalysis.score.toFixed(1),
verdict: verdict(),
};
res.json({
data: result,
});
} catch (e) {
res.json({
data: {
error_msg: e,
},
});
}
};

// On checkout button click in store page, execute reCAPTCHA Enterprise assessment and take action according to the score.
const onStoreCheckout = async (req, res) => {
try {
// <!-- ATTENTION: reCAPTCHA Example (Server Part 1/2) Starts -->
const assessmentResponse = await createAssessment(
context.project_id,
context.site_key,
req.body.recaptcha_cred.token
);

const verdict = function () {
// Check if the token is valid, score is above threshold score and the action equals expected.
if (
assessmentResponse.tokenProperties.valid &&
assessmentResponse.riskAnalysis.score > SAMPLE_THRESHOLD_SCORE &&
assessmentResponse.tokenProperties.action ===
PROPERTIES.get('recaptcha_action.store')
) {
// Check if the cart contains items and proceed to checkout and payment.
// let items = req.body.recaptcha_cred.items
// Business logic.
// Classify the action as not bad.
return NOT_BAD;
} else {
// If any of the above condition fails, trigger email/ phone verification flow.
// Classify the action as bad.
return BAD;
}
};
// <!-- ATTENTION: reCAPTCHA Example (Server Part 1/2) Ends -->

// Return the risk score.
const result = {
score: assessmentResponse.riskAnalysis.score.toFixed(1),
verdict: verdict(),
};
res.json({
data: result,
});
} catch (e) {
res.json({
data: {
error_msg: e,
},
});
}
};

// On comment submit, execute reCAPTCHA Enterprise assessment and take action according to the score.
const onCommentSubmit = async (req, res) => {
try {
// <!-- ATTENTION: reCAPTCHA Example (Server Part 1/2) Starts -->
const assessmentResponse = await createAssessment(
context.project_id,
context.site_key,
req.body.recaptcha_cred.token
);

const verdict = function () {
// Check if the token is valid, score is above threshold score and the action equals expected.
if (
assessmentResponse.tokenProperties.valid &&
assessmentResponse.riskAnalysis.score > SAMPLE_THRESHOLD_SCORE &&
assessmentResponse.tokenProperties.action ===
PROPERTIES.get('recaptcha_action.comment')
) {
// Check if comment has safe language and proceed to store in database.
// let comment = req.body.recaptcha_cred.comment
// Business logic.
// Classify the action as not bad.
return NOT_BAD;
} else {
// If any of the above condition fails, trigger email/ phone verification flow.
// Classify the action as bad.
return BAD;
}
};
// <!-- ATTENTION: reCAPTCHA Example (Server Part 1/2) Ends -->

// Return the risk score.
const result = {
score: assessmentResponse.riskAnalysis.score.toFixed(1),
verdict: verdict(),
};
res.json({
data: assessmentData,
success: true,
data: result,
});
} catch (e) {
res.json({
error_msg: e,
success: false,
data: {
error_msg: e,
},
});
}
};

module.exports = {
homeController,
storeController,
loginController,
commentController,
signupController,
gameController,
assessmentController,
home,
signup,
login,
store,
comment,
game,
onHomepageLoad,
onSignup,
onLogin,
onStoreCheckout,
onCommentSubmit,
};
2 changes: 1 addition & 1 deletion recaptcha_enterprise/demosite/app/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -36,5 +36,5 @@ app.use('/static', express.static('static'));
app.use('/', router);

app.listen(port, () => {
console.log(`ReCAPTCHA Demosite app listening on port ${port}`);
console.log(`reCAPTCHA Demosite app listening on port ${port}`);
});
36 changes: 19 additions & 17 deletions recaptcha_enterprise/demosite/app/package.json
Original file line number Diff line number Diff line change
@@ -1,19 +1,21 @@
{
"name": "recaptcha-demosite",
"description": "",
"version": "1.0.0",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
"repository": {
"type": "git",
"url": "https://github.com/googleapis/nodejs-recaptcha-enterprise.git"
},
"license": "MIT",
"dependencies": {
"@google-cloud/recaptcha-enterprise": "^3.0.0",
"body-parser": "^1.20.0",
"express": "^4.18.1",
"mustache-express": "^1.3.2"
}
"name": "recaptcha-demosite",
"description": "One-click deployment solution for recaptcha enterprise",
"version": "1.0.0",
"license": "Apache-2.0",
"author": "Google Inc.",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
"repository": {
"type": "git",
"url": "https://github.com/googleapis/nodejs-recaptcha-enterprise.git"
},
"dependencies": {
"@google-cloud/recaptcha-enterprise": "^3.0.0",
"body-parser": "^1.20.0",
"express": "^4.18.1",
"mustache-express": "^1.3.2",
"properties-reader": "^2.2.0"
}
}
Loading

0 comments on commit 39d8e05

Please sign in to comment.