Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion source/server/routes/auth/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ router.post("/login",
useJSON,
useURLEncoded,
useTemplateProperties,
postLogin,
wrap(postLogin),
);
router.get("/login/:username/link", isAdministrator, wrap(getLoginLink));
router.post("/login/:username/link", either(isAdministrator, rateLimit({
Expand Down
23 changes: 23 additions & 0 deletions source/server/routes/auth/login.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -127,6 +127,29 @@ describe("/auth/login", function(){
.expect(400);
expect(res.body).to.have.property("message").match(/Bad username format/i);
});

it("returns unauthorized status for bad password", async function(){
this.agent = request.agent(this.server);
const res = await this.agent.post("/auth/login")
.send({username: user.username, password: "badPassword"})
.set("Content-Type", "application/json")
.set("Accept", "application/json")
.expect(401);

expect(res.body).to.have.property("code", 401);
expect(res.body).to.have.property("message").match(/Bad password/i);
});
it("returns unauthorized status for bad password", async function(){
this.agent = request.agent(this.server);
const res = await this.agent.post("/auth/login")
.send({username: "badUsername", password: "12345678"})
.set("Content-Type", "application/json")
.set("Accept", "application/json")
.expect(401);

expect(res.body).to.have.property("code", 401);
expect(res.body).to.have.property("message").match(/Username not found/i);
});

it("can logout", async function(){
let agent = request.agent(this.server);
Expand Down
68 changes: 35 additions & 33 deletions source/server/routes/auth/login.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
* Handler for login flow. Used for automated AND interactive login flows, which makes it a bit more complicated
* Due to this, it handles (most of) its own errors contrary to most handlers.
*/
export function postLogin(req :Request, res :Response, next :NextFunction){
export async function postLogin(req :Request, res :Response){
const {sessionMaxAge} = getLocals(req);
let userManager = getUserManager(req);
let {redirect} = req.query;
Expand All @@ -19,54 +19,56 @@
else if(typeof username !="string") throw new BadRequestError("Bad username format");
if(!password) throw new BadRequestError("Password not provided");
else if(typeof password !="string") throw new BadRequestError("Bad password format");

userManager.getUserByNamePassword(username, password).then(user=>{
let safeUser = User.safe(user);
Object.assign(
(req as any).session as any,
{expires: Date.now() + sessionMaxAge},
safeUser
);
return safeUser;
}).then((safeUser)=>{
if(redirect && typeof redirect === "string"){
return res.redirect(302, validateRedirect(req, redirect).toString());
}else{
res.format({
"application/json": ()=> {
res.status(200).send(safeUser);
},
"text/html": ()=>{
res.redirect(302, "/ui/");
},
"text/plain": ()=>{
res.status(200).send(`${safeUser.username} (${safeUser.uid})`);
},
});
}

}, (e)=>{
if(e instanceof NotFoundError){
let user: User;
try{
user = await userManager.getUserByNamePassword(username, password);
}catch(e: any){
if(e instanceof NotFoundError){ //cast NotFound as Unauthorized
e = new UnauthorizedError(`Username not found`);
}
const code :number = e.code ?? 500;
const rawMessage = (e instanceof HTTPError)? e.message.slice(6): e.message;
res.status(code);

res.format({
"application/json": ()=> {
res.status(200).send({ code, message: `${e.name}: ${e.message}` });
res.send({ code, message: `${e.name}: ${e.message}` });
},
"text/html": ()=>{
res.render("login", {
error: rawMessage,
});
},
"text/plain": ()=>{
res.status(code).send(e.message);
res.send(e.message);
},
});
return; //Stop here.
}

let safeUser = User.safe(user);

//Update user session accordingly
Object.assign(
(req as any).session as any,
{expires: Date.now() + sessionMaxAge},
safeUser
);

if(redirect && typeof redirect === "string"){
return res.redirect(302, validateRedirect(req, redirect).toString());
}else{
res.format({
"application/json": ()=> {
res.status(200).send(safeUser);
},
"text/html": ()=>{
res.redirect(302, "/ui/");
},
"text/plain": ()=>{
res.status(200).send(`${safeUser.username} (${safeUser.uid})`);
},
});
}).catch(next);
}
}

export async function getLogin(req :Request, res:Response){
Expand Down
Loading