v1.18.x
Barış Soner Uşaklı 4 years ago
commit 7069735aa2

@ -159,7 +159,7 @@
"eslint-plugin-import": "2.22.1",
"grunt": "1.3.0",
"grunt-contrib-watch": "1.1.0",
"husky": "4.3.6",
"husky": "4.3.7",
"jsdom": "16.4.0",
"lint-staged": "10.5.3",
"mocha": "8.2.1",

@ -58,4 +58,5 @@ get:
type: string
title:
type: string
- $ref: ../../../components/schemas/Breadcrumbs.yaml#/Breadcrumbs
- $ref: ../../../components/schemas/CommonProps.yaml#/CommonProps

@ -42,6 +42,8 @@ tags:
paths:
/ping:
$ref: 'write/ping.yaml'
/utilities/login:
$ref: 'write/login.yaml'
/users/:
$ref: 'write/users.yaml'
/users/{uid}:

@ -0,0 +1,30 @@
post:
tags:
- utilities
summary: verify login credentials
description: |
This route accepts a username/password or email/password pair (dependent on forum settings), returning a standard user object if credentials are validated successfully.
requestBody:
content:
application/json:
schema:
type: object
properties:
username:
type: string
example: admin
password:
type: string
example: '123456'
responses:
'200':
description: credentials successfully validated
content:
application/json:
schema:
type: object
properties:
status:
$ref: ../components/schemas/Status.yaml#/Status
response:
$ref: ../components/schemas/UserObject.yaml#/UserObjectSlim

@ -226,7 +226,7 @@ authenticationController.login = function (req, res, next) {
plugins.hooks.fire('filter:login.check', { req: req, res: res, userData: req.body }, (err) => {
if (err) {
return helpers.noScriptErrors(req, res, err.message, 403);
return (res.locals.noScriptErrors || helpers.noScriptErrors)(req, res, err.message, 403);
}
if (req.body.username && utils.isEmailValid(req.body.username) && loginWith.includes('email')) {
async.waterfall([
@ -235,14 +235,14 @@ authenticationController.login = function (req, res, next) {
},
function (username, next) {
req.body.username = username || req.body.username;
continueLogin(req, res, next);
(res.locals.continueLogin || continueLogin)(req, res, next);
},
], next);
} else if (loginWith.includes('username') && !validator.isEmail(req.body.username)) {
continueLogin(req, res, next);
(res.locals.continueLogin || continueLogin)(req, res, next);
} else {
err = '[[error:wrong-login-type-' + loginWith + ']]';
helpers.noScriptErrors(req, res, err, 500);
(res.locals.noScriptErrors || helpers.noScriptErrors)(req, res, err, 400);
}
});
};

@ -461,6 +461,11 @@ helpers.generateError = (statusCode, message) => {
payload.status.message = message || 'HTTPS is required for requests to the write api, please re-send your request via HTTPS';
break;
case 429:
payload.status.code = 'too-many-requests';
payload.status.message = message || 'You have made too many requests, please try again later';
break;
case 500:
payload.status.code = 'internal-server-error';
payload.status.message = message || payload.status.message;

@ -9,3 +9,4 @@ Write.topics = require('./topics');
Write.posts = require('./posts');
Write.admin = require('./admin');
Write.files = require('./files');
Write.utilities = require('./utilities');

@ -0,0 +1,51 @@
'use strict';
const user = require('../../user');
const authenticationController = require('../authentication');
const slugify = require('../../slugify');
const helpers = require('../helpers');
const Utilities = module.exports;
Utilities.ping = {};
Utilities.ping.get = (req, res) => {
helpers.formatApiResponse(200, res, {
pong: true,
});
};
Utilities.ping.post = (req, res) => {
helpers.formatApiResponse(200, res, {
uid: req.user.uid,
received: req.body,
});
};
Utilities.login = (req, res) => {
res.locals.continueLogin = async (req, res) => {
const { username, password } = req.body;
const userslug = slugify(username);
const uid = await user.getUidByUserslug(userslug);
let ok = false;
try {
ok = await user.isPasswordCorrect(uid, password, req.ip);
} catch (err) {
if (err.message === '[[error:account-locked]]') {
return helpers.formatApiResponse(429, res, err);
}
}
if (ok) {
const userData = await user.getUsers([uid], uid);
helpers.formatApiResponse(200, res, userData.pop());
} else {
helpers.formatApiResponse(403, res);
}
};
res.locals.noScriptErrors = (req, res, err, statusCode) => {
helpers.formatApiResponse(statusCode, res, new Error(err));
};
authenticationController.login(req, res);
};

@ -4,6 +4,7 @@ const winston = require('winston');
const meta = require('../../meta');
const plugins = require('../../plugins');
const middleware = require('../../middleware');
const writeControllers = require('../../controllers/write');
const helpers = require('../../controllers/helpers');
const Write = module.exports;
@ -38,19 +39,10 @@ Write.reload = async (params) => {
router.use('/api/v3/posts', require('./posts')());
router.use('/api/v3/admin', require('./admin')());
router.use('/api/v3/files', require('./files')());
router.use('/api/v3/utilities', require('./utilities')());
router.get('/api/v3/ping', function (req, res) {
helpers.formatApiResponse(200, res, {
pong: true,
});
});
router.post('/api/v3/ping', middleware.authenticate, function (req, res) {
helpers.formatApiResponse(200, res, {
uid: req.user.uid,
received: req.body,
});
});
router.get('/api/v3/ping', writeControllers.utilities.ping.get);
router.post('/api/v3/ping', middleware.authenticate, writeControllers.utilities.ping.post);
/**
* Plugins can add routes to the Write API by attaching a listener to the

@ -0,0 +1,16 @@
'use strict';
const router = require('express').Router();
const middleware = require('../../middleware');
const controllers = require('../../controllers');
const routeHelpers = require('../helpers');
const setupApiRoute = routeHelpers.setupApiRoute;
module.exports = function () {
// The "ping" routes are mounted at root level, but for organizational purposes, the controllers are in `utilities.js`
setupApiRoute(router, 'post', '/login', [middleware.checkRequired.bind(null, ['username', 'password'])], controllers.write.utilities.login);
return router;
};

@ -332,7 +332,7 @@ describe('API', async () => {
}
});
it('should resolve with a 200 when called', async () => {
it('should not error out when called', async () => {
await setupData();
if (csrfToken) {
@ -372,7 +372,7 @@ describe('API', async () => {
});
}
} catch (e) {
assert(!e, `${method.toUpperCase()} ${path} resolved with ${e.message}`);
assert(!e, `${method.toUpperCase()} ${path} errored with: ${e.message}`);
}
});

@ -422,7 +422,7 @@ describe('authentication', function () {
loginUser('ginger@nodebb.org', '123456', function (err, response, body) {
meta.config.allowLoginWith = 'username-email';
assert.ifError(err);
assert.equal(response.statusCode, 500);
assert.equal(response.statusCode, 400);
assert.equal(body, '[[error:wrong-login-type-username]]');
done();
});

Loading…
Cancel
Save