зеркало из https://github.com/mozilla/CSOL-site.git
146 строки
4.7 KiB
JavaScript
146 строки
4.7 KiB
JavaScript
const jwt = require('jwt-simple');
|
|
const util = require('util');
|
|
const db = require('../db');
|
|
const learners = db.model('Learner');
|
|
const guardians = db.model('Guardian');
|
|
const mandrill = require('../mandrill');
|
|
const openbadger = require('../openbadger');
|
|
const url = require('url');
|
|
const logger = require('../logger');
|
|
const s3 = require('../s3');
|
|
|
|
const JWT_SECRET = process.env.CSOL_OPENBADGER_SECRET;
|
|
const CSOL_HOST = process.env.CSOL_HOST;
|
|
|
|
if (!JWT_SECRET)
|
|
throw new Error('Must specify CSOL_OPENBADGER_SECRET in the environment');
|
|
|
|
if (!CSOL_HOST)
|
|
throw new Error('Must specify CSOL_HOST in the environment');
|
|
|
|
function handleIssuedClaim(email, code, callback) {
|
|
learners.find({ where: { email: email } }).success(function(learner) {
|
|
if (learner !== null && !learner.underage) {
|
|
// email matched a >13 learner. Can immediately claim the badge.
|
|
openbadger.claim({ code: code, email: email }, function (err, data) {
|
|
return callback(err);
|
|
});
|
|
}
|
|
else {
|
|
var claimUrl = url.format({
|
|
protocol : 'http:',
|
|
host : url.parse(CSOL_HOST).host,
|
|
pathname: '/claim',
|
|
query : { code: code }
|
|
});
|
|
|
|
openbadger.getBadgeFromCode({ code: code, email: email }, function(err, badgeData) {
|
|
if (err)
|
|
return callback(err);
|
|
|
|
if (learner === null) {
|
|
guardians.find({ where: { email: email} }).success(function(guardian) {
|
|
if (guardian !== null) {
|
|
// email matched a guardian. unknown child.
|
|
mandrill.send('<13 badge claim', { claimUrl: claimUrl, badgeName: badgeData.badge.name }, email, function(err) {
|
|
return callback(err);
|
|
});
|
|
}
|
|
else {
|
|
// email did not match any existing guardian or learner.
|
|
mandrill.send('unknown badge claim', { claimUrl: claimUrl, badgeName: badgeData.badge.name }, email, function(err) {
|
|
return callback(err);
|
|
});
|
|
}
|
|
});
|
|
}
|
|
else if (learner.underage) {
|
|
learner.getGuardian().complete(function (err, guardian) {
|
|
if (err)
|
|
return callback(err);
|
|
|
|
// email matched an underage learner. Email the guardian
|
|
mandrill.send('<13 badge claim with name', { claimUrl: claimUrl, earnerName: learner.username, badgeName: badgeData.badge.name }, guardian.email, function(err) {
|
|
return callback(err)
|
|
});
|
|
});
|
|
}
|
|
});
|
|
}
|
|
});
|
|
}
|
|
|
|
function respondWithForbidden(res, reason) {
|
|
return res.send(403, { status: 'forbidden', reason: reason });
|
|
}
|
|
|
|
function auth(req, res, next) {
|
|
const param = req.method === "GET" ? req.query : req.body;
|
|
const token = param.auth;
|
|
const email = param.email;
|
|
|
|
const now = Date.now()/1000|0;
|
|
var decodedToken, msg;
|
|
if (!token)
|
|
return respondWithForbidden(res, 'missing mandatory `auth` param');
|
|
try {
|
|
decodedToken = jwt.decode(token, JWT_SECRET);
|
|
} catch(err) {
|
|
return respondWithForbidden(res, 'error decoding JWT: ' + err.message);
|
|
}
|
|
if (decodedToken.prn !== email) {
|
|
msg = '`prn` mismatch: given %s, expected %s';
|
|
return respondWithForbidden(res, util.format(msg, decodedToken.prn, email));
|
|
}
|
|
|
|
if (!decodedToken.exp)
|
|
return respondWithForbidden(res, 'Token must have exp (expiration) set');
|
|
|
|
if (decodedToken.exp < now)
|
|
return respondWithForbidden(res, 'Token has expired');
|
|
|
|
return next();
|
|
}
|
|
|
|
module.exports = function (app) {
|
|
app.post('/notify/claim', auth, function (req, res, next) {
|
|
var claimCode = req.body.claimCode;
|
|
var email = req.body.email;
|
|
|
|
if (req.body.isTesting)
|
|
return module.exports.testHandler(req, res, next);
|
|
|
|
if (!claimCode)
|
|
return res.send(500, { status: 'error', error: 'No claimCode provided' });
|
|
|
|
claimCode = claimCode.trim();
|
|
|
|
handleIssuedClaim(email, claimCode, function(err) {
|
|
if (err) {
|
|
logger.log('info', 'Error encountered while handling claim code %s for user %s: %s', claimCode, email, err.toString());
|
|
return res.send(500, { status: 'error', error: 'An error occurred while attempting to handle this claim notification.' });
|
|
}
|
|
|
|
return res.send(200, { status: 'ok' });
|
|
});
|
|
});
|
|
};
|
|
|
|
module.exports.testHandler = function(req, res, next) {
|
|
var claimCode = req.body.claimCode;
|
|
|
|
if (req.body.isTesting !== true)
|
|
return res.send(200, "body.isTesting !== true");
|
|
|
|
if (!(claimCode && typeof(claimCode) == "string"))
|
|
return res.send(200, "body.claimCode is empty");
|
|
|
|
s3.putBuffer(new Buffer(claimCode), '/' + claimCode, {
|
|
'Content-Type': 'text/plain'
|
|
}, function(err) {
|
|
if (err) return res.send(200, "s3 putbuffer failed");
|
|
|
|
return res.send(200, "S3_ITEM_CREATED");
|
|
});
|
|
};
|