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

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

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

@ -42,6 +42,8 @@ tags:
paths: paths:
/ping: /ping:
$ref: 'write/ping.yaml' $ref: 'write/ping.yaml'
/utilities/login:
$ref: 'write/login.yaml'
/users/: /users/:
$ref: 'write/users.yaml' $ref: 'write/users.yaml'
/users/{uid}: /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) => { plugins.hooks.fire('filter:login.check', { req: req, res: res, userData: req.body }, (err) => {
if (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')) { if (req.body.username && utils.isEmailValid(req.body.username) && loginWith.includes('email')) {
async.waterfall([ async.waterfall([
@ -235,14 +235,14 @@ authenticationController.login = function (req, res, next) {
}, },
function (username, next) { function (username, next) {
req.body.username = username || req.body.username; req.body.username = username || req.body.username;
continueLogin(req, res, next); (res.locals.continueLogin || continueLogin)(req, res, next);
}, },
], next); ], next);
} else if (loginWith.includes('username') && !validator.isEmail(req.body.username)) { } else if (loginWith.includes('username') && !validator.isEmail(req.body.username)) {
continueLogin(req, res, next); (res.locals.continueLogin || continueLogin)(req, res, next);
} else { } else {
err = '[[error:wrong-login-type-' + loginWith + ']]'; 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'; payload.status.message = message || 'HTTPS is required for requests to the write api, please re-send your request via HTTPS';
break; 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: case 500:
payload.status.code = 'internal-server-error'; payload.status.code = 'internal-server-error';
payload.status.message = message || payload.status.message; payload.status.message = message || payload.status.message;

@ -9,3 +9,4 @@ Write.topics = require('./topics');
Write.posts = require('./posts'); Write.posts = require('./posts');
Write.admin = require('./admin'); Write.admin = require('./admin');
Write.files = require('./files'); 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 meta = require('../../meta');
const plugins = require('../../plugins'); const plugins = require('../../plugins');
const middleware = require('../../middleware'); const middleware = require('../../middleware');
const writeControllers = require('../../controllers/write');
const helpers = require('../../controllers/helpers'); const helpers = require('../../controllers/helpers');
const Write = module.exports; const Write = module.exports;
@ -38,19 +39,10 @@ Write.reload = async (params) => {
router.use('/api/v3/posts', require('./posts')()); router.use('/api/v3/posts', require('./posts')());
router.use('/api/v3/admin', require('./admin')()); router.use('/api/v3/admin', require('./admin')());
router.use('/api/v3/files', require('./files')()); router.use('/api/v3/files', require('./files')());
router.use('/api/v3/utilities', require('./utilities')());
router.get('/api/v3/ping', function (req, res) { router.get('/api/v3/ping', writeControllers.utilities.ping.get);
helpers.formatApiResponse(200, res, { router.post('/api/v3/ping', middleware.authenticate, writeControllers.utilities.ping.post);
pong: true,
});
});
router.post('/api/v3/ping', middleware.authenticate, function (req, res) {
helpers.formatApiResponse(200, res, {
uid: req.user.uid,
received: req.body,
});
});
/** /**
* Plugins can add routes to the Write API by attaching a listener to the * 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(); await setupData();
if (csrfToken) { if (csrfToken) {
@ -372,7 +372,7 @@ describe('API', async () => {
}); });
} }
} catch (e) { } 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) { loginUser('ginger@nodebb.org', '123456', function (err, response, body) {
meta.config.allowLoginWith = 'username-email'; meta.config.allowLoginWith = 'username-email';
assert.ifError(err); assert.ifError(err);
assert.equal(response.statusCode, 500); assert.equal(response.statusCode, 400);
assert.equal(body, '[[error:wrong-login-type-username]]'); assert.equal(body, '[[error:wrong-login-type-username]]');
done(); done();
}); });

Loading…
Cancel
Save