diff --git a/src/oauth2views/account_create.ejs b/src/oauth2views/account_create.ejs
new file mode 100644
index 000000000..794328932
--- /dev/null
+++ b/src/oauth2views/account_create.ejs
@@ -0,0 +1,48 @@
+<% include header %>
+
+
+
+
+
+
+
+ Welcome to <%= cloudronName %>.
+
+
+
+
+
+
Create your account by providing an email address.
+
+
+
+
You have received an email invitation to this Cloudron to finish the signup.
+
+
+
+
+<% include footer %>
diff --git a/src/routes/oauth2.js b/src/routes/oauth2.js
index 882f14f89..b6c67bd25 100644
--- a/src/routes/oauth2.js
+++ b/src/routes/oauth2.js
@@ -11,6 +11,7 @@ var appdb = require('../appdb'),
DatabaseError = require('../databaseerror'),
debug = require('debug')('box:routes/oauth2'),
eventlog = require('../eventlog.js'),
+ generatePassword = require('../password.js').generate,
hat = require('hat'),
HttpError = require('connect-lastmile').HttpError,
middleware = require('../middleware/index.js'),
@@ -357,6 +358,77 @@ function accountSetup(req, res, next) {
});
}
+// -> POST /api/v1/session/account/setup
+function accountSetup(req, res, next) {
+ assert.strictEqual(typeof req.body, 'object');
+
+ if (typeof req.body.resetToken !== 'string') return next(new HttpError(400, 'Missing resetToken'));
+ if (typeof req.body.password !== 'string') return next(new HttpError(400, 'Missing password'));
+ if (typeof req.body.username !== 'string') return next(new HttpError(400, 'Missing username'));
+ if (typeof req.body.displayName !== 'string') return next(new HttpError(400, 'Missing displayName'));
+
+ debug('accountSetup: with token %s.', req.body.resetToken);
+
+ user.getByResetToken(req.body.resetToken, function (error, userObject) {
+ if (error) return sendError(req, res, 'Invalid Reset Token');
+
+ var data = _.pick(req.body, 'username', 'displayName');
+ user.update(userObject.id, data, auditSource(req), function (error) {
+ if (error && error.reason === UserError.ALREADY_EXISTS) return renderAccountSetupSite(res, req, userObject, 'Username already exists');
+ if (error && error.reason === UserError.BAD_FIELD) return renderAccountSetupSite(res, req, userObject, error.message);
+ if (error && error.reason === UserError.NOT_FOUND) return renderAccountSetupSite(res, req, userObject, 'No such user');
+ if (error) return next(new HttpError(500, error));
+
+ userObject.username = req.body.username;
+ userObject.displayName = req.body.displayName;
+
+ // setPassword clears the resetToken
+ user.setPassword(userObject.id, req.body.password, function (error, result) {
+ if (error && error.reason === UserError.BAD_FIELD) return renderAccountSetupSite(res, req, userObject, error.message);
+
+ if (error) return next(new HttpError(500, error));
+
+ res.redirect(util.format('%s?accessToken=%s&expiresAt=%s', config.adminOrigin(), result.token, result.expiresAt));
+ });
+ });
+ });
+}
+
+function renderAccountCreateSite(res, req, error, success) {
+ renderTemplate(res, 'account_create', {
+ error: error,
+ success: !!success,
+ csrf: req.csrfToken(),
+ title: 'Account Create'
+ });
+}
+
+// -> GET /api/v1/session/account/create.html
+function accountCreateSite(req, res) {
+ renderAccountCreateSite(res, req, '', '');
+}
+
+// -> POST /api/v1/session/account/create
+function accountCreate(req, res, next) {
+ assert.strictEqual(typeof req.body, 'object');
+
+ if (typeof req.body.email !== 'string') return next(new HttpError(400, 'Missing email'));
+
+ debug('accountCreate: with email %s.', req.body.email);
+
+ var ip = req.headers['x-forwarded-for'] || req.connection.remoteAddress || null;
+ var auditSource = { ip: ip, username: req.body.email, userId: null };
+
+ user.create('', generatePassword(), req.body.email, '', auditSource, { sendInvite: true }, function (error, result) {
+ if (error && error.reason === UserError.ALREADY_EXISTS) return renderAccountCreateSite(res, req, 'User with this email address already exists');
+ if (error) return sendError(req, res, 'Internal Error');
+
+ debug('accountCreate: success for email %s now with id %s', req.body.remail, result.id);
+
+ renderAccountCreateSite(res, req, '', true);
+ });
+}
+
// -> GET /api/v1/session/password/reset.html
function passwordResetSite(req, res, next) {
if (!req.query.reset_token) return next(new HttpError(400, 'Missing reset_token'));
@@ -555,6 +627,8 @@ exports = module.exports = {
passwordReset: passwordReset,
accountSetupSite: accountSetupSite,
accountSetup: accountSetup,
+ accountCreateSite: accountCreateSite,
+ accountCreate: accountCreate,
authorization: authorization,
token: token,
validateRequestedScopes: validateRequestedScopes,
diff --git a/src/server.js b/src/server.js
index d7b9b32c7..b3c457516 100644
--- a/src/server.js
+++ b/src/server.js
@@ -148,6 +148,8 @@ function initializeExpressSync() {
router.post('/api/v1/session/password/reset', csrf, routes.oauth2.passwordReset);
router.get ('/api/v1/session/account/setup.html', csrf, routes.oauth2.accountSetupSite);
router.post('/api/v1/session/account/setup', csrf, routes.oauth2.accountSetup);
+ router.get ('/api/v1/session/account/create.html', csrf, routes.oauth2.accountCreateSite);
+ router.post('/api/v1/session/account/create', csrf, routes.oauth2.accountCreate);
// oauth2 routes
router.get ('/api/v1/oauth/dialog/authorize', routes.oauth2.authorization);