"use strict" ;
const Promise = require ( "bluebird" ) ;
const defaultValue = require ( "default-value" ) ;
const expressPromiseRouter = require ( "express-promise-router" ) ;
const errors = require ( "../../../errors" ) ;
const validate = require ( "../../../middlewares/validate-payload" ) ;
const processDeviceID = require ( "../../../process-device-id" ) ;
module . exports = function ( state ) {
const userInteractiveAuthentication = require ( "../../../middlewares/user-interactive-authentication" ) ( state ) ;
let { db , knex , configuration , fullyQualifyUser } = state ;
let router = expressPromiseRouter ( ) ;
function validateRegisterPayload ( payload ) {
let { assertProperties , isPresent , isString , isOneOf , isBoolean } = require ( "../../../validator-lib" ) ;
assertProperties ( payload , {
kind : [ isOneOf ( "user" , "guest" ) ] ,
device _id : [ isString ] ,
initial _device _display _name : [ isString ] ,
username : [ isPresent , isString , ( username ) => {
if ( ! /^[a-z0-9._=/-]+$/ . test ( username ) ) {
throw new errors . InvalidUsername ( "Usernames may only contain a-z, 0-9, and . _ = - /" ) ;
} else if ( username . startsWith ( "_" ) ) {
throw new errors . ExclusiveResource ( "Usernames starting with _ are reserved for bridges" ) ;
}
} ] ,
password : [ isPresent , isString ] , /* FIXME: Password strength */
inhibit _login : [ isBoolean ] ,
bind _email : [ isBoolean ]
} ) ;
}
let registerUIAMiddleware = userInteractiveAuthentication ( {
/* FIXME: Modify settings based on eg. CAPTCHAs being enabled */
required : false ,
flows : [
{ stages : [ "m.login.dummy" ] }
]
} ) ;
router . post ( "/r0/register" , registerUIAMiddleware , validate ( validateRegisterPayload ) , ( req , res ) => {
// https://matrix.org/docs/spec/client_server/r0.4.0.html#post-matrix-client-r0-register
// Register for an account on this homeserver. This API endpoint uses the User-Interactive Authentication API.
/* FIXME: Rate-limit */
if ( req . body . kind === "guest" ) {
/* TODO: Re-evaluate this, once it becomes clearer how to deal with guest users and peeking across federation (ref. https://github.com/matrix-org/matrix-doc/pull/1777) */
throw new errors . Forbidden ( "Guest registrations are disabled on this server" ) ;
} else {
let inhibitLogin = defaultValue ( req . body . inhibit _login , false ) ;
/* FILEBUG: Default for bind_email is not clearly specified in spec */
/* FIXME: Actually implement e-mail binding on identity server */
let bindEmail = defaultValue ( req . body . bind _email , false ) ;
let deviceId = processDeviceID ( req . body . deviceID ) ;
return knex . transaction ( ( transaction ) => {
return Promise . try ( ( ) => {
return db . users . create ( {
type : "user" ,
username : req . body . username ,
password : req . body . password
} , transaction ) ;
} ) . then ( ( user ) => {
return Promise . try ( ( ) => {
if ( ! inhibitLogin ) {
return db . devices . createDeviceSession ( {
name : req . body . initial _device _display _name ,
deviceId : deviceId ,
userId : user . id
} , transaction ) ;
}
} ) . then ( ( device ) => {
let sessionDetails = ( device != null )
? { access _token : device . token , device _id : device . device _id }
: { } ;
res . send ( {
user _id : fullyQualifyUser ( user . username ) ,
home _server : configuration . hostname ,
... sessionDetails
} ) ;
} ) ;
} ) ;
} ) . catch ( { name : "UniqueConstraintViolationError" , table : "users" , column : "username" } , ( _error ) => {
throw new errors . UserExists ( "That username is already taken" ) ;
} ) ;
}
} ) ;
return router ;
}