Skip to content
This repository has been archived by the owner on Dec 14, 2023. It is now read-only.

Commit

Permalink
Merge branch 'master' into enchanment/bruteforce-protection
Browse files Browse the repository at this point in the history
  • Loading branch information
butlerx committed Dec 3, 2016
2 parents 2718b26 + 4f4c9b5 commit 0d39144
Show file tree
Hide file tree
Showing 22 changed files with 923 additions and 111 deletions.
2 changes: 2 additions & 0 deletions circle.yml
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,8 @@ dependencies:
test:
override:
- npm run test
post:
- curl -sSL https://download.sourceclear.com/ci.sh | bash
deployment:
production:
branch: master
Expand Down
4 changes: 1 addition & 3 deletions config/config.js
Original file line number Diff line number Diff line change
Expand Up @@ -28,9 +28,7 @@ module.exports = function () {
'postgresql-store': pgConfig(),
'email-notifications': {
sendemail: true,
sendFrom: 'The CoderDojo Team <[email protected]>',
email: {
}
sendFrom: 'The CoderDojo Team <[email protected]>'
},
mailtrap: {
folder: path.resolve(__dirname + '/../email-templates'),
Expand Down
24 changes: 21 additions & 3 deletions config/perm/profiles.js
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ module.exports = function(){
}, {
role: 'basic-user',
userType: 'champion',
extendedUserTypes: true,
customValidator: [{
role: 'cd-dojos',
cmd: 'belongs_to_dojo'
Expand Down Expand Up @@ -116,7 +117,22 @@ module.exports = function(){
}],
'load_parents_for_user': [
{ role: 'basic-user',
userType: 'champion'
userType: 'champion',
extendedUserTypes: true
},
{ role: 'basic-user',
customValidator: [{
role: 'cd-dojos',
cmd: 'have_permissions',
perm: 'dojo-admin'
}]
},
{ role: 'basic-user',
customValidator: [{
role: 'cd-dojos',
cmd: 'have_permissions',
perm: 'ticketing-admin'
}]
},
{ role: 'basic-user',
customValidator: [{
Expand All @@ -137,7 +153,8 @@ module.exports = function(){
},
{
role: 'basic-user',
userType: 'champion'
userType: 'champion',
extendedUserTypes: true
},
{
role: 'basic-user',
Expand All @@ -153,7 +170,8 @@ module.exports = function(){
userType: 'parent-guardian'
},
{ role: 'basic-user',
userType: 'champion'
userType: 'champion',
extendedUserTypes: true
},
{ role: 'basic-user',
customValidator:[ {
Expand Down
14 changes: 6 additions & 8 deletions config/perm/users.js
Original file line number Diff line number Diff line change
Expand Up @@ -19,10 +19,6 @@ module.exports = function(){
cmd: 'is_parent_of',
}]
}],
'list': [{
role: 'basic-user',
userTypes: 'champion'
}],
'register': [{
role: 'none',
}],
Expand All @@ -35,10 +31,8 @@ module.exports = function(){
//NOTE: isn't perm a customVal now ?
customValidator: [{
role: 'cd-dojos',
cmd: 'is_having_perm',
param: {
perm: 'dojo-admin'
}
cmd: 'have_permissions',
perm: 'dojo-admin'
}]
}],

Expand Down Expand Up @@ -82,6 +76,7 @@ module.exports = function(){
}, {
role: 'basic-user',
userType: 'champion',
extendedUserTypes: true,
customValidator: [{
role: 'cd-dojos',
cmd: 'belongs_to_dojo'
Expand Down Expand Up @@ -124,5 +119,8 @@ module.exports = function(){
'kpi_number_of_youth_females_registered': [{
role: 'cdf-admin',
}],
'get_lms_link': [{
role: 'basic-user'
}],
};
};
2 changes: 1 addition & 1 deletion email-notifications.js
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ module.exports = function (options) {
var subject = args.subject;
var subjectVariables = args.subjectVariables || [];
var subjectTranslation;
if (options.sendemail && options.email) {
if (options.sendemail) {
var emailCode = args.code + args.locality;
if (!fs.existsSync(path.join(__dirname, '/email-templates/', emailCode))) emailCode = args.code + 'en_US';
if (!args.to) return done(null, {ok: false, why: 'No recipient set.'});
Expand Down
72 changes: 72 additions & 0 deletions lib/users/lms/award-badge.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
'use strict';
var async = require('async');
var _ = require('lodash');

/**
* Webhook handler to award badges based on courses
* Courses "Code" must correspond to the badge slug
* @param {Object} certificate contains all the info, header/user/course passed
* ie: {"header":{"source":"LearnUpon","version":1,"webhookId":2213843,"attempt":2,"lastAttemptAt":"2016-09-01T10:33:32Z","webHookType":"course_completion","signature":"5736605a1627415455de6f7ca50e7e9d"},"user":{"userId":12345,"lastName":null,"firstName":null,"email":"qq@example.com","username":null,"customData":null},"enrollmentId":42,"courseId":42,"courseName":"CoderDojo Ethos: Implementation and Practice","courseReferenceCode":"coderdojo-ethos:-implementation-and-practice","courseMetaData":null,"modules":[{"id":42,"type":"scorm","name":"CoderDojo Ethos: Implementation and Practice","status":"passed","percentage":100.0,"dateCompleted":null,"attempts":null,"isKnowledgeCheck":false}],"credits":[],"courseAccessExpiresAt":null,"certification":false,"certificationName":null,"certExpiresAt":null,"wasRecertified":false,"dateEnrolled":"2016-08-29T12:02:38Z","dateStarted":"2016-09-01T10:30:50Z","dateCompleted":"2016-09-01T10:32:28Z","percentage":100,"enrollmentStatus":"passed","hasAttemptsRemaining":false}
*/
function awardLMSBadge (args, cb) {
var seneca = this;
var plugin = args.role;
var certif = args;
var user = certif.user;

function checkTestStatus (waterfallCb) {
if (certif.header.webHookType !== 'course_completion') {
return cb(null, {ok: false, why: 'Unhandled webhook'});
}
if (!_.every(certif.modules, {'status': 'passed'}) &&
!_.every(certif.modules, {'status': 'completed'}) &&
!_.includes(['completed', 'passed'], certif.enrollmentStatus) ) {
return cb(null, {ok: false, why: 'Unhandled status'});
}
waterfallCb(null, certif.courseReferenceCode);
}

function getBadge (badgeName, waterfallCb) {
seneca.act({role: 'cd-badges', cmd: 'getBadge', slug: badgeName},
function (err, badge) {
if (err) return cb(err);
waterfallCb(null, badge);
});
}

function getUser (badge, waterfallCb) {
seneca.act({role: 'cd-users', cmd: 'list', query: {lmsId: user.userId}},
function (err, sysUser) {
if (err) return cb(err);
if (_.isEmpty(sysUser)) return cb(null, {ok: false, why: 'LMSUser not found'});
return waterfallCb(null, sysUser[0], badge);
});
}

function awardBadge (sysUser, badge, waterfallCb) {
var applicationData = {
user: sysUser,
badge: badge.badge,
emailSubject: 'You have been awarded a new CoderDojo digital badge!'
};
seneca.act({role: 'cd-badges', cmd: 'sendBadgeApplication',
applicationData: applicationData,
user: {id: null}
},
function (err, user) {
if (err) return cb(err);
waterfallCb();
});
}


async.waterfall([
checkTestStatus,
getBadge,
getUser,
awardBadge
], cb);

}

module.exports = awardLMSBadge;
32 changes: 32 additions & 0 deletions lib/users/lms/check-certificate-authenticity.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
'use strict';
var _ = require('lodash');
var crypto = require('crypto');

/**
* Verify the validity of a LMS certificate by comparing the signature of this cert
* to the value of its hash + our shared private key
* @param {String} certificate the certificate as a string
* @param {String} signature extracted expected hash
*/
function checkValidity (args, cb) {
var seneca = this;
var hash = crypto.createHash('md5');
var webhookSecret = process.env.LMS_WEBHOOK_SECRET;
var signature = args.signature;
var certif = args.certif;
var stringCertif = certif + ':' + webhookSecret;
hash.update(stringCertif);
var digest = hash.digest('hex');
if ( !_.isEmpty(webhookSecret)){
if ( digest !== signature){
cb(null, {ok: false, why: 'Invalid signature', http$:{status: 401}});
} else {
cb(null, {ok: true});
}
} else {
cb(new Error('Missing Webhook Secret'));
}
}


module.exports = checkValidity;
Loading

0 comments on commit 0d39144

Please sign in to comment.