Moved api tests to oauth2.

This commit is contained in:
SamTV12345 2024-03-25 21:17:33 +01:00
parent 6f3f127808
commit 85bb520355
16 changed files with 501 additions and 214 deletions

81
pnpm-lock.yaml generated
View file

@ -193,6 +193,9 @@ importers:
jsonminify: jsonminify:
specifier: 0.4.2 specifier: 0.4.2
version: 0.4.2 version: 0.4.2
jsonwebtoken:
specifier: ^9.0.2
version: 9.0.2
languages4translatewiki: languages4translatewiki:
specifier: 0.1.3 specifier: 0.1.3
version: 0.1.3 version: 0.1.3
@ -290,6 +293,9 @@ importers:
'@types/jsdom': '@types/jsdom':
specifier: ^21.1.6 specifier: ^21.1.6
version: 21.1.6 version: 21.1.6
'@types/jsonwebtoken':
specifier: ^9.0.6
version: 9.0.6
'@types/mocha': '@types/mocha':
specifier: ^10.0.6 specifier: ^10.0.6
version: 10.0.6 version: 10.0.6
@ -2263,6 +2269,12 @@ packages:
resolution: {integrity: sha512-dRLjCWHYg4oaA77cxO64oO+7JwCwnIzkZPdrrC71jQmQtlhM556pwKo5bUzqvZndkVbeFLIIi+9TC40JNF5hNQ==} resolution: {integrity: sha512-dRLjCWHYg4oaA77cxO64oO+7JwCwnIzkZPdrrC71jQmQtlhM556pwKo5bUzqvZndkVbeFLIIi+9TC40JNF5hNQ==}
dev: true dev: true
/@types/jsonwebtoken@9.0.6:
resolution: {integrity: sha512-/5hndP5dCjloafCXns6SZyESp3Ldq7YjH3zwzwczYnjxIT0Fqzk5ROSYVGfFyczIue7IUEj8hkvLbPoLQ18vQw==}
dependencies:
'@types/node': 20.11.30
dev: true
/@types/keygrip@1.0.6: /@types/keygrip@1.0.6:
resolution: {integrity: sha512-lZuNAY9xeJt7Bx4t4dx0rYCDqGPW8RXhQZK1td7d4H6E9zYbLoOtjBvfwdTKpsyxQI/2jv+armjX/RW+ZNpXOQ==} resolution: {integrity: sha512-lZuNAY9xeJt7Bx4t4dx0rYCDqGPW8RXhQZK1td7d4H6E9zYbLoOtjBvfwdTKpsyxQI/2jv+armjX/RW+ZNpXOQ==}
dev: true dev: true
@ -3099,6 +3111,10 @@ packages:
update-browserslist-db: 1.0.13(browserslist@4.23.0) update-browserslist-db: 1.0.13(browserslist@4.23.0)
dev: true dev: true
/buffer-equal-constant-time@1.0.1:
resolution: {integrity: sha512-zRpUiDwd/xk6ADqPMATG8vc9VPrkck7T07OIx0gnjmJAnHnTVXNQG3vfvWNuiZIkwu9KrKdA1iJKfsfTVxE6NA==}
dev: false
/buffer-from@1.1.2: /buffer-from@1.1.2:
resolution: {integrity: sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==} resolution: {integrity: sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==}
dev: false dev: false
@ -3556,6 +3572,12 @@ packages:
tslib: 2.6.2 tslib: 2.6.2
dev: true dev: true
/ecdsa-sig-formatter@1.0.11:
resolution: {integrity: sha512-nagl3RYrbNv6kQkeJIpt6NJZy8twLB/2vtz6yN9Z4vRKHN4/QZJIEbqohALSgwKdnksuY3k5Addp5lg8sVoVcQ==}
dependencies:
safe-buffer: 5.2.1
dev: false
/ee-first@1.1.1: /ee-first@1.1.1:
resolution: {integrity: sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow==} resolution: {integrity: sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow==}
dev: false dev: false
@ -5235,10 +5257,41 @@ packages:
resolution: {integrity: sha512-lz1nOH69GbsVHeVgEdvyavc/33oymY1AZwtePMiMj4HZPMbP5OIKK3zT9INMWjwua/V4Z4yq7wSlBbSG+g4AEw==} resolution: {integrity: sha512-lz1nOH69GbsVHeVgEdvyavc/33oymY1AZwtePMiMj4HZPMbP5OIKK3zT9INMWjwua/V4Z4yq7wSlBbSG+g4AEw==}
dev: true dev: true
/jsonwebtoken@9.0.2:
resolution: {integrity: sha512-PRp66vJ865SSqOlgqS8hujT5U4AOgMfhrwYIuIhfKaoSCZcirrmASQr8CX7cUg+RMih+hgznrjp99o+W4pJLHQ==}
engines: {node: '>=12', npm: '>=6'}
dependencies:
jws: 3.2.2
lodash.includes: 4.3.0
lodash.isboolean: 3.0.3
lodash.isinteger: 4.0.4
lodash.isnumber: 3.0.3
lodash.isplainobject: 4.0.6
lodash.isstring: 4.0.1
lodash.once: 4.1.1
ms: 2.1.3
semver: 7.6.0
dev: false
/just-extend@6.2.0: /just-extend@6.2.0:
resolution: {integrity: sha512-cYofQu2Xpom82S6qD778jBDpwvvy39s1l/hrYij2u9AMdQcGRpaBu6kY4mVhuno5kJVi1DAz4aiphA2WI1/OAw==} resolution: {integrity: sha512-cYofQu2Xpom82S6qD778jBDpwvvy39s1l/hrYij2u9AMdQcGRpaBu6kY4mVhuno5kJVi1DAz4aiphA2WI1/OAw==}
dev: true dev: true
/jwa@1.4.1:
resolution: {integrity: sha512-qiLX/xhEEFKUAJ6FiBMbes3w9ATzyk5W7Hvzpa/SLYdxNtng+gcurvrI7TbACjIXlsJyr05/S1oUhZrc63evQA==}
dependencies:
buffer-equal-constant-time: 1.0.1
ecdsa-sig-formatter: 1.0.11
safe-buffer: 5.2.1
dev: false
/jws@3.2.2:
resolution: {integrity: sha512-YHlZCB6lMTllWDtSPHz/ZXTsi8S00usEV6v1tjq8tOUZzw7DpSDWVXjXDre6ed1w/pd495ODpHZYSdkRTsa0HA==}
dependencies:
jwa: 1.4.1
safe-buffer: 5.2.1
dev: false
/kebab-case@1.0.2: /kebab-case@1.0.2:
resolution: {integrity: sha512-7n6wXq4gNgBELfDCpzKc+mRrZFs7D+wgfF5WRFLNAr4DA/qtr9Js8uOAVAfHhuLMfAcQ0pRKqbpjx+TcJVdE1Q==} resolution: {integrity: sha512-7n6wXq4gNgBELfDCpzKc+mRrZFs7D+wgfF5WRFLNAr4DA/qtr9Js8uOAVAfHhuLMfAcQ0pRKqbpjx+TcJVdE1Q==}
dev: true dev: true
@ -5357,9 +5410,37 @@ packages:
resolution: {integrity: sha512-z+Uw/vLuy6gQe8cfaFWD7p0wVv8fJl3mbzXh33RS+0oW2wvUqiRXiQ69gLWSLpgB5/6sU+r6BlQR0MBILadqTQ==} resolution: {integrity: sha512-z+Uw/vLuy6gQe8cfaFWD7p0wVv8fJl3mbzXh33RS+0oW2wvUqiRXiQ69gLWSLpgB5/6sU+r6BlQR0MBILadqTQ==}
dev: true dev: true
/lodash.includes@4.3.0:
resolution: {integrity: sha512-W3Bx6mdkRTGtlJISOvVD/lbqjTlPPUDTMnlXZFnVwi9NKJ6tiAk6LVdlhZMm17VZisqhKcgzpO5Wz91PCt5b0w==}
dev: false
/lodash.isboolean@3.0.3:
resolution: {integrity: sha512-Bz5mupy2SVbPHURB98VAcw+aHh4vRV5IPNhILUCsOzRmsTmSQ17jIuqopAentWoehktxGd9e/hbIXq980/1QJg==}
dev: false
/lodash.isinteger@4.0.4:
resolution: {integrity: sha512-DBwtEWN2caHQ9/imiNeEA5ys1JoRtRfY3d7V9wkqtbycnAmTvRRmbHKDV4a0EYc678/dia0jrte4tjYwVBaZUA==}
dev: false
/lodash.isnumber@3.0.3:
resolution: {integrity: sha512-QYqzpfwO3/CWf3XP+Z+tkQsfaLL/EnUlXWVkIk5FUPc4sBdTehEqZONuyRt2P67PXAk+NXmTBcc97zw9t1FQrw==}
dev: false
/lodash.isplainobject@4.0.6:
resolution: {integrity: sha512-oSXzaWypCMHkPC3NvBEaPHf0KsA5mvPrOPgQWDsbg8n7orZ290M0BmC/jgRZ4vcJ6DTAhjrsSYgdsW/F+MFOBA==}
dev: false
/lodash.isstring@4.0.1:
resolution: {integrity: sha512-0wJxfxH1wgO3GrbuP+dTTk7op+6L41QCXbGINEmD+ny/G/eCqGzxyCsh7159S+mgDDcoarnBw6PC1PS5+wUGgw==}
dev: false
/lodash.merge@4.6.2: /lodash.merge@4.6.2:
resolution: {integrity: sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==} resolution: {integrity: sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==}
/lodash.once@4.1.1:
resolution: {integrity: sha512-Sb487aTOCr9drQVL8pIxOzVhafOjZN9UU54hiN8PU3uAiSV7lx1yYNpbNmex2PK6dSJoNTSJUUswT651yww3Mg==}
dev: false
/lodash@4.17.21: /lodash@4.17.21:
resolution: {integrity: sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==} resolution: {integrity: sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==}
dev: false dev: false

View file

@ -21,30 +21,12 @@
import {MapArrayType} from "../types/MapType"; import {MapArrayType} from "../types/MapType";
const absolutePaths = require('../utils/AbsolutePaths');
import fs from 'fs';
const api = require('../db/API'); const api = require('../db/API');
import log4js from 'log4js';
const padManager = require('../db/PadManager'); const padManager = require('../db/PadManager');
const randomString = require('../utils/randomstring');
const argv = require('../utils/Cli').argv;
import createHTTPError from 'http-errors'; import createHTTPError from 'http-errors';
import {Http2ServerRequest, Http2ServerResponse} from "node:http2";
const apiHandlerLogger = log4js.getLogger('APIHandler'); import {publicKeyExported} from "../security/OAuth2Provider";
import {jwtVerify} from "jose";
// ensure we have an apikey
let apikey:string|null = null;
const apikeyFilename = absolutePaths.makeAbsolute(argv.apikey || './APIKEY.txt');
try {
apikey = fs.readFileSync(apikeyFilename, 'utf8');
apiHandlerLogger.info(`Api key file read from: "${apikeyFilename}"`);
} catch (e) {
apiHandlerLogger.info(
`Api key file "${apikeyFilename}" not found. Creating with random contents.`);
apikey = randomString(32);
fs.writeFileSync(apikeyFilename, apikey!, 'utf8');
}
// a list of all functions // a list of all functions
const version:MapArrayType<any> = {}; const version:MapArrayType<any> = {};
@ -174,14 +156,14 @@ type APIFields = {
} }
/** /**
* Handles a HTTP API call * Handles an HTTP API call
* @param {String} apiVersion the version of the api * @param {String} apiVersion the version of the api
* @param {String} functionName the name of the called function * @param {String} functionName the name of the called function
* @param fields the params of the called function * @param fields the params of the called function
* @req express request object * @param req express request object
* @res express response object * @param res express response object
*/ */
exports.handle = async function (apiVersion: string, functionName: string, fields: APIFields) { exports.handle = async function (apiVersion: string, functionName: string, fields: APIFields, req: Http2ServerRequest, res: Http2ServerResponse) {
// say goodbye if this is an unknown API version // say goodbye if this is an unknown API version
if (!(apiVersion in version)) { if (!(apiVersion in version)) {
throw new createHTTPError.NotFound('no such api version'); throw new createHTTPError.NotFound('no such api version');
@ -192,13 +174,20 @@ exports.handle = async function (apiVersion: string, functionName: string, field
throw new createHTTPError.NotFound('no such function'); throw new createHTTPError.NotFound('no such function');
} }
// check the api key! if(!req.headers.authorization) {
fields.apikey = fields.apikey || fields.api_key;
if (fields.apikey !== apikey!.trim()) {
throw new createHTTPError.Unauthorized('no or wrong API Key'); throw new createHTTPError.Unauthorized('no or wrong API Key');
} }
try {
await jwtVerify(req.headers.authorization!.replace("Bearer ", ""), publicKeyExported!, {algorithms: ['RS256'],
requiredClaims: ["admin"]})
} catch (e) {
throw new createHTTPError.Unauthorized('no or wrong API Key');
}
// sanitize any padIDs before continuing // sanitize any padIDs before continuing
if (fields.padID) { if (fields.padID) {
fields.padID = await padManager.sanitizePadId(fields.padID); fields.padID = await padManager.sanitizePadId(fields.padID);
@ -217,7 +206,3 @@ exports.handle = async function (apiVersion: string, functionName: string, field
// call the api function // call the api function
return api[functionName].apply(this, functionParams); return api[functionName].apply(this, functionParams);
}; };
exports.exportedForTestingOnly = {
apiKey: apikey,
};

View file

@ -657,7 +657,7 @@ exports.expressPreSession = async (hookName:string, {app}:any) => {
} }
// start and bind to express // start and bind to express
api.init(); await api.init();
app.use(apiRoot, async (req:any, res:any) => { app.use(apiRoot, async (req:any, res:any) => {
let response = null; let response = null;
try { try {

View file

@ -1,6 +1,6 @@
import {ArgsExpressType} from "../types/ArgsExpressType"; import {ArgsExpressType} from "../types/ArgsExpressType";
import Provider, {Account, Configuration, InteractionResults} from 'oidc-provider'; import Provider, {Account, Configuration} from 'oidc-provider';
import {generateKeyPair, exportJWK} from 'jose' import {generateKeyPair, exportJWK, KeyLike} from 'jose'
import MemoryAdapter from "./OIDCAdapter"; import MemoryAdapter from "./OIDCAdapter";
import path from "path"; import path from "path";
const settings = require('../utils/Settings'); const settings = require('../utils/Settings');
@ -8,8 +8,8 @@ import {IncomingForm} from 'formidable'
import express, {Request, Response} from 'express'; import express, {Request, Response} from 'express';
import {format} from 'url' import {format} from 'url'
import {ParsedUrlQuery} from "node:querystring"; import {ParsedUrlQuery} from "node:querystring";
import cors from 'cors'
import {Http2ServerRequest, Http2ServerResponse} from "node:http2"; import {Http2ServerRequest, Http2ServerResponse} from "node:http2";
const configuration: Configuration = { const configuration: Configuration = {
scopes: ['openid', 'profile', 'email'], scopes: ['openid', 'profile', 'email'],
findAccount: async (ctx, id) => { findAccount: async (ctx, id) => {
@ -27,14 +27,25 @@ const configuration: Configuration = {
const account = usersArray1.find((user) => user.username === id); const account = usersArray1.find((user) => user.username === id);
if(account === undefined) {
return undefined
}
if (account.is_admin) {
return { return {
accountId: id, accountId: id,
claims: () => ({ claims: () => ({
sub: id, sub: id,
test: "test", admin: true
admin: account?.is_admin
}) })
} as Account } as Account
} else {
return {
accountId: id,
claims: () => ({
sub: id,
})
} as Account
}
}, },
ttl:{ ttl:{
AccessToken: 1 * 60 * 60, // 1 hour in seconds AccessToken: 1 * 60 * 60, // 1 hour in seconds
@ -59,16 +70,17 @@ const configuration: Configuration = {
}; };
export let publicKeyExported: KeyLike|null
export let privateKeyExported: KeyLike|null
/* /*
This function is used to initialize the OAuth2 provider This function is used to initialize the OAuth2 provider
*/ */
export const expressCreateServer = async (hookName: string, args: ArgsExpressType, cb: Function) => { export const expressCreateServer = async (hookName: string, args: ArgsExpressType, cb: Function) => {
const {privateKey} = await generateKeyPair('RS256'); const {privateKey, publicKey} = await generateKeyPair('RS256');
const privateKeyJWK = await exportJWK(privateKey); const privateKeyJWK = await exportJWK(privateKey);
// Use cors middleware publicKeyExported = publicKey
args.app.use(cors({ privateKeyExported = privateKey
origin: ['http://localhost:3001', 'https://oauth.pstmn.io'], // replace with your allowed origins
}));
const oidc = new Provider('http://localhost:9001', { const oidc = new Provider('http://localhost:9001', {
...configuration, jwks: { ...configuration, jwks: {

View file

@ -34,7 +34,6 @@
"axios": "^1.6.8", "axios": "^1.6.8",
"clean-css": "^5.3.3", "clean-css": "^5.3.3",
"cookie-parser": "^1.4.6", "cookie-parser": "^1.4.6",
"cors": "^2.8.5",
"cross-spawn": "^7.0.3", "cross-spawn": "^7.0.3",
"ejs": "^3.1.9", "ejs": "^3.1.9",
"etherpad-require-kernel": "^1.0.16", "etherpad-require-kernel": "^1.0.16",
@ -50,6 +49,7 @@
"js-cookie": "^3.0.5", "js-cookie": "^3.0.5",
"jsdom": "^24.0.0", "jsdom": "^24.0.0",
"jsonminify": "0.4.2", "jsonminify": "0.4.2",
"jsonwebtoken": "^9.0.2",
"languages4translatewiki": "0.1.3", "languages4translatewiki": "0.1.3",
"live-plugin-manager-pnpm": "^0.18.1", "live-plugin-manager-pnpm": "^0.18.1",
"lodash.clonedeep": "4.5.0", "lodash.clonedeep": "4.5.0",
@ -89,6 +89,7 @@
"@types/formidable": "^3.4.5", "@types/formidable": "^3.4.5",
"@types/http-errors": "^2.0.4", "@types/http-errors": "^2.0.4",
"@types/jsdom": "^21.1.6", "@types/jsdom": "^21.1.6",
"@types/jsonwebtoken": "^9.0.6",
"@types/mocha": "^10.0.6", "@types/mocha": "^10.0.6",
"@types/node": "^20.11.30", "@types/node": "^20.11.30",
"@types/oidc-provider": "^8.4.4", "@types/oidc-provider": "^8.4.4",

View file

@ -13,18 +13,20 @@ const server = require('../../node/server');
const setCookieParser = require('set-cookie-parser'); const setCookieParser = require('set-cookie-parser');
const settings = require('../../node/utils/Settings'); const settings = require('../../node/utils/Settings');
import supertest from 'supertest'; import supertest from 'supertest';
import TestAgent from "supertest/lib/agent";
import {Http2Server} from "node:http2";
import {SignJWT} from "jose";
import {privateKeyExported} from "../../node/security/OAuth2Provider";
const webaccess = require('../../node/hooks/express/webaccess'); const webaccess = require('../../node/hooks/express/webaccess');
const backups:MapArrayType<any> = {}; const backups:MapArrayType<any> = {};
let agentPromise:Promise<any>|null = null; let agentPromise:Promise<any>|null = null;
exports.apiKey = apiHandler.exportedForTestingOnly.apiKey; export let agent: TestAgent|null = null;
exports.agent = null; export let baseUrl:string|null = null;
exports.baseUrl = null; export let httpServer: Http2Server|null = null;
exports.httpServer = null; export const logger = log4js.getLogger('test');
exports.logger = log4js.getLogger('test');
const logger = exports.logger;
const logLevel = logger.level; const logLevel = logger.level;
// Mocha doesn't monitor unhandled Promise rejections, so convert them to uncaught exceptions. // Mocha doesn't monitor unhandled Promise rejections, so convert them to uncaught exceptions.
@ -33,10 +35,24 @@ process.on('unhandledRejection', (reason: string) => { throw reason; });
before(async function () { before(async function () {
this.timeout(60000); this.timeout(60000);
await exports.init(); await init();
}); });
exports.init = async function () {
export const generateJWTToken = () => {
const jwt = new SignJWT({
sub: 'admin',
jti: '123',
exp: Math.floor(Date.now() / 1000) + 60 * 60,
aud: 'account',
iss: 'http://localhost:9001',
admin: true
})
jwt.setProtectedHeader({alg: 'RS256'})
return jwt.sign(privateKeyExported!)
}
export const init = async function () {
if (agentPromise != null) return await agentPromise; if (agentPromise != null) return await agentPromise;
let agentResolve; let agentResolve;
agentPromise = new Promise((resolve) => { agentResolve = resolve; }); agentPromise = new Promise((resolve) => { agentResolve = resolve; });
@ -53,11 +69,13 @@ exports.init = async function () {
settings.ip = 'localhost'; settings.ip = 'localhost';
settings.importExportRateLimiting = {max: 999999}; settings.importExportRateLimiting = {max: 999999};
settings.commitRateLimiting = {duration: 0.001, points: 1e6}; settings.commitRateLimiting = {duration: 0.001, points: 1e6};
exports.httpServer = await server.start(); httpServer = await server.start();
exports.baseUrl = `http://localhost:${exports.httpServer.address().port}`; // @ts-ignore
logger.debug(`HTTP server at ${exports.baseUrl}`); baseUrl = `http://localhost:${httpServer!.address()!.port}`;
logger.debug(`HTTP server at ${baseUrl}`);
// Create a supertest user agent for the HTTP server. // Create a supertest user agent for the HTTP server.
exports.agent = supertest(exports.baseUrl); agent = supertest(baseUrl)
//.set('Authorization', `Bearer ${await generateJWTToken()}`);
// Speed up authn tests. // Speed up authn tests.
backups.authnFailureDelayMs = webaccess.authnFailureDelayMs; backups.authnFailureDelayMs = webaccess.authnFailureDelayMs;
webaccess.authnFailureDelayMs = 0; webaccess.authnFailureDelayMs = 0;
@ -69,8 +87,8 @@ exports.init = async function () {
await server.exit(); await server.exit();
}); });
agentResolve!(exports.agent); agentResolve!(agent);
return exports.agent; return agent;
}; };
/** /**
@ -81,7 +99,7 @@ exports.init = async function () {
* @param {string} event - The socket.io Socket event to listen for. * @param {string} event - The socket.io Socket event to listen for.
* @returns The argument(s) passed to the event handler. * @returns The argument(s) passed to the event handler.
*/ */
exports.waitForSocketEvent = async (socket: any, event:string) => { export const waitForSocketEvent = async (socket: any, event:string) => {
const errorEvents = [ const errorEvents = [
'error', 'error',
'connect_error', 'connect_error',
@ -136,7 +154,7 @@ exports.waitForSocketEvent = async (socket: any, event:string) => {
* nullish, no cookies are passed to the server. * nullish, no cookies are passed to the server.
* @returns {io.Socket} A socket.io client Socket object. * @returns {io.Socket} A socket.io client Socket object.
*/ */
exports.connect = async (res:any = null) => { export const connect = async (res:any = null) => {
// Convert the `set-cookie` header(s) into a `cookie` header. // Convert the `set-cookie` header(s) into a `cookie` header.
const resCookies = (res == null) ? {} : setCookieParser.parse(res, {map: true}); const resCookies = (res == null) ? {} : setCookieParser.parse(res, {map: true});
const reqCookieHdr = Object.entries(resCookies).map( const reqCookieHdr = Object.entries(resCookies).map(
@ -148,14 +166,14 @@ exports.connect = async (res:any = null) => {
if (res) { if (res) {
padId = res.req.path.split('/p/')[1]; padId = res.req.path.split('/p/')[1];
} }
const socket = io(`${exports.baseUrl}/`, { const socket = io(`${baseUrl}/`, {
forceNew: true, // Different tests will have different query parameters. forceNew: true, // Different tests will have different query parameters.
// socketio.js-client on node.js doesn't support cookies (see https://git.io/JU8u9), so the // socketio.js-client on node.js doesn't support cookies (see https://git.io/JU8u9), so the
// express_sid cookie must be passed as a query parameter. // express_sid cookie must be passed as a query parameter.
query: {cookie: reqCookieHdr, padId}, query: {cookie: reqCookieHdr, padId},
}); });
try { try {
await exports.waitForSocketEvent(socket, 'connect'); await waitForSocketEvent(socket, 'connect');
} catch (e) { } catch (e) {
socket.close(); socket.close();
throw e; throw e;
@ -173,7 +191,7 @@ exports.connect = async (res:any = null) => {
* @param token * @param token
* @returns The CLIENT_VARS message from the server. * @returns The CLIENT_VARS message from the server.
*/ */
exports.handshake = async (socket: any, padId:string, token = padutils.generateAuthorToken()) => { export const handshake = async (socket: any, padId:string, token = padutils.generateAuthorToken()) => {
logger.debug('sending CLIENT_READY...'); logger.debug('sending CLIENT_READY...');
socket.emit('message', { socket.emit('message', {
component: 'pad', component: 'pad',
@ -183,7 +201,7 @@ exports.handshake = async (socket: any, padId:string, token = padutils.generateA
token, token,
}); });
logger.debug('waiting for CLIENT_VARS response...'); logger.debug('waiting for CLIENT_VARS response...');
const msg = await exports.waitForSocketEvent(socket, 'message'); const msg = await waitForSocketEvent(socket, 'message');
logger.debug('received CLIENT_VARS message'); logger.debug('received CLIENT_VARS message');
return msg; return msg;
}; };
@ -191,7 +209,7 @@ exports.handshake = async (socket: any, padId:string, token = padutils.generateA
/** /**
* Convenience wrapper around `socket.send()` that waits for acknowledgement. * Convenience wrapper around `socket.send()` that waits for acknowledgement.
*/ */
exports.sendMessage = async (socket: any, message:any) => await new Promise<void>((resolve, reject) => { export const sendMessage = async (socket: any, message:any) => await new Promise<void>((resolve, reject) => {
socket.emit('message', message, (errInfo:{ socket.emit('message', message, (errInfo:{
name: string, name: string,
message: string, message: string,
@ -210,7 +228,7 @@ exports.sendMessage = async (socket: any, message:any) => await new Promise<void
/** /**
* Convenience function to send a USER_CHANGES message. Waits for acknowledgement. * Convenience function to send a USER_CHANGES message. Waits for acknowledgement.
*/ */
exports.sendUserChanges = async (socket:any, data:any) => await exports.sendMessage(socket, { export const sendUserChanges = async (socket:any, data:any) => await sendMessage(socket, {
type: 'COLLABROOM', type: 'COLLABROOM',
component: 'pad', component: 'pad',
data: { data: {
@ -232,8 +250,8 @@ exports.sendUserChanges = async (socket:any, data:any) => await exports.sendMess
* common.sendUserChanges(socket, {baseRev: rev, changeset}), * common.sendUserChanges(socket, {baseRev: rev, changeset}),
* ]); * ]);
*/ */
exports.waitForAcceptCommit = async (socket:any, wantRev: number) => { export const waitForAcceptCommit = async (socket:any, wantRev: number) => {
const msg = await exports.waitForSocketEvent(socket, 'message'); const msg = await waitForSocketEvent(socket, 'message');
assert.deepEqual(msg, { assert.deepEqual(msg, {
type: 'COLLABROOM', type: 'COLLABROOM',
data: { data: {
@ -252,7 +270,7 @@ const alphabet = 'abcdefghijklmnopqrstuvwxyz';
* @param {string} [charset] - Characters to pick from. * @param {string} [charset] - Characters to pick from.
* @returns {string} * @returns {string}
*/ */
exports.randomString = (len: number = 10, charset: string = `${alphabet}${alphabet.toUpperCase()}0123456789`): string => { export const randomString = (len: number = 10, charset: string = `${alphabet}${alphabet.toUpperCase()}0123456789`): string => {
let ret = ''; let ret = '';
while (ret.length < len) ret += charset[Math.floor(Math.random() * charset.length)]; while (ret.length < len) ret += charset[Math.floor(Math.random() * charset.length)];
return ret; return ret;

View file

@ -27,7 +27,7 @@ const makeid = () => {
const testPadId = makeid(); const testPadId = makeid();
const endPoint = (point:string) => `/api/${apiVersion}/${point}?apikey=${apiKey}`; const endPoint = (point:string) => `/api/${apiVersion}/${point}`;
describe(__filename, function () { describe(__filename, function () {
before(async function () { agent = await common.init(); }); before(async function () { agent = await common.init(); });

View file

@ -6,17 +6,18 @@
* TODO: maybe unify those two files and merge in a single one. * TODO: maybe unify those two files and merge in a single one.
*/ */
import {generateJWTToken} from "../../common";
const assert = require('assert').strict; const assert = require('assert').strict;
const common = require('../../common'); const common = require('../../common');
const fs = require('fs'); const fs = require('fs');
const fsp = fs.promises; const fsp = fs.promises;
let agent:any; let agent:any;
const apiKey = common.apiKey;
let apiVersion = 1; let apiVersion = 1;
const testPadId = makeid(); const testPadId = makeid();
const endPoint = (point:string, version?:number) => `/api/${version || apiVersion}/${point}?apikey=${apiKey}`; const endPoint = (point:string, version?:number) => `/api/${version || apiVersion}/${point}`;
describe(__filename, function () { describe(__filename, function () {
before(async function () { agent = await common.init(); }); before(async function () { agent = await common.init(); });
@ -24,12 +25,14 @@ describe(__filename, function () {
describe('Sanity checks', function () { describe('Sanity checks', function () {
it('can connect', async function () { it('can connect', async function () {
await agent.get('/api/') await agent.get('/api/')
.set("Authorization", await generateJWTToken())
.expect(200) .expect(200)
.expect('Content-Type', /json/); .expect('Content-Type', /json/);
}); });
it('finds the version tag', async function () { it('finds the version tag', async function () {
const res = await agent.get('/api/') const res = await agent.get('/api/')
.set("Authorization", await generateJWTToken())
.expect(200); .expect(200);
apiVersion = res.body.currentVersion; apiVersion = res.body.currentVersion;
assert(apiVersion); assert(apiVersion);
@ -38,14 +41,16 @@ describe(__filename, function () {
it('errors with invalid APIKey', async function () { it('errors with invalid APIKey', async function () {
// This is broken because Etherpad doesn't handle HTTP codes properly see #2343 // This is broken because Etherpad doesn't handle HTTP codes properly see #2343
// If your APIKey is password you deserve to fail all tests anyway // If your APIKey is password you deserve to fail all tests anyway
await agent.get(`/api/${apiVersion}/createPad?apikey=password&padID=test`) await agent.get(`/api/${apiVersion}/createPad?padID=test`)
.set("Authorization", (await generateJWTToken()).substring(0,10))
.expect(401); .expect(401);
}); });
}); });
describe('Tests', function () { describe('Tests', function () {
it('creates a new Pad', async function () { it('creates a new Pad', async function () {
const res = await agent.get(`${endPoint('createPad')}&padID=${testPadId}`) const res = await agent.get(`${endPoint('createPad')}?padID=${testPadId}`)
.set("Authorization", await generateJWTToken())
.expect(200) .expect(200)
.expect('Content-Type', /json/); .expect('Content-Type', /json/);
assert.equal(res.body.code, 0); assert.equal(res.body.code, 0);
@ -53,6 +58,7 @@ describe(__filename, function () {
it('Sets the HTML of a Pad attempting to weird utf8 encoded content', async function () { it('Sets the HTML of a Pad attempting to weird utf8 encoded content', async function () {
const res = await agent.post(endPoint('setHTML')) const res = await agent.post(endPoint('setHTML'))
.set("Authorization", await generateJWTToken())
.send({ .send({
padID: testPadId, padID: testPadId,
html: await fsp.readFile('tests/backend/specs/api/emojis.html', 'utf8'), html: await fsp.readFile('tests/backend/specs/api/emojis.html', 'utf8'),
@ -63,7 +69,8 @@ describe(__filename, function () {
}); });
it('get the HTML of Pad with emojis', async function () { it('get the HTML of Pad with emojis', async function () {
const res = await agent.get(`${endPoint('getHTML')}&padID=${testPadId}`) const res = await agent.get(`${endPoint('getHTML')}?padID=${testPadId}`)
.set("Authorization", await generateJWTToken())
.expect(200) .expect(200)
.expect('Content-Type', /json/); .expect('Content-Type', /json/);
assert.match(res.body.data.html, /&#127484/); assert.match(res.body.data.html, /&#127484/);

View file

@ -1,17 +1,18 @@
'use strict'; 'use strict';
import {generateJWTToken} from "../../common";
const common = require('../../common'); const common = require('../../common');
import {strict as assert} from "assert"; import {strict as assert} from "assert";
let agent:any; let agent:any;
const apiKey = common.apiKey;
let apiVersion = 1; let apiVersion = 1;
let authorID = ''; let authorID = '';
const padID = makeid(); const padID = makeid();
const timestamp = Date.now(); const timestamp = Date.now();
const endPoint = (point:string) => `/api/${apiVersion}/${point}?apikey=${apiKey}`; const endPoint = (point:string) => `/api/${apiVersion}/${point}`;
describe(__filename, function () { describe(__filename, function () {
before(async function () { agent = await common.init(); }); before(async function () { agent = await common.init(); });
@ -42,16 +43,18 @@ describe(__filename, function () {
describe('Chat functionality', function () { describe('Chat functionality', function () {
it('creates a new Pad', async function () { it('creates a new Pad', async function () {
await agent.get(`${endPoint('createPad')}&padID=${padID}`) await agent.get(`${endPoint('createPad')}?padID=${padID}`)
.set("authorization", await generateJWTToken())
.expect(200)
.expect((res:any) => { .expect((res:any) => {
if (res.body.code !== 0) throw new Error('Unable to create new Pad'); if (res.body.code !== 0) throw new Error('Unable to create new Pad');
}) })
.expect('Content-Type', /json/) .expect('Content-Type', /json/);
.expect(200);
}); });
it('Creates an author with a name set', async function () { it('Creates an author with a name set', async function () {
await agent.get(endPoint('createAuthor')) await agent.get(endPoint('createAuthor'))
.set("authorization", await generateJWTToken())
.expect((res:any) => { .expect((res:any) => {
if (res.body.code !== 0 || !res.body.data.authorID) { if (res.body.code !== 0 || !res.body.data.authorID) {
throw new Error('Unable to create author'); throw new Error('Unable to create author');
@ -63,7 +66,8 @@ describe(__filename, function () {
}); });
it('Gets the head of chat before the first chat msg', async function () { it('Gets the head of chat before the first chat msg', async function () {
await agent.get(`${endPoint('getChatHead')}&padID=${padID}`) await agent.get(`${endPoint('getChatHead')}?padID=${padID}`)
.set("authorization", await generateJWTToken())
.expect((res:any) => { .expect((res:any) => {
if (res.body.data.chatHead !== -1) throw new Error('Chat Head Length is wrong'); if (res.body.data.chatHead !== -1) throw new Error('Chat Head Length is wrong');
if (res.body.code !== 0) throw new Error('Unable to get chat head'); if (res.body.code !== 0) throw new Error('Unable to get chat head');
@ -73,8 +77,9 @@ describe(__filename, function () {
}); });
it('Adds a chat message to the pad', async function () { it('Adds a chat message to the pad', async function () {
await agent.get(`${endPoint('appendChatMessage')}&padID=${padID}&text=blalblalbha` + await agent.get(`${endPoint('appendChatMessage')}?padID=${padID}&text=blalblalbha` +
`&authorID=${authorID}&time=${timestamp}`) `&authorID=${authorID}&time=${timestamp}`)
.set("authorization", await generateJWTToken())
.expect((res:any) => { .expect((res:any) => {
if (res.body.code !== 0) throw new Error('Unable to create chat message'); if (res.body.code !== 0) throw new Error('Unable to create chat message');
}) })
@ -83,7 +88,8 @@ describe(__filename, function () {
}); });
it('Gets the head of chat', async function () { it('Gets the head of chat', async function () {
await agent.get(`${endPoint('getChatHead')}&padID=${padID}`) await agent.get(`${endPoint('getChatHead')}?padID=${padID}`)
.set("authorization", await generateJWTToken())
.expect((res:any) => { .expect((res:any) => {
if (res.body.data.chatHead !== 0) throw new Error('Chat Head Length is wrong'); if (res.body.data.chatHead !== 0) throw new Error('Chat Head Length is wrong');
@ -94,7 +100,8 @@ describe(__filename, function () {
}); });
it('Gets Chat History of a Pad', async function () { it('Gets Chat History of a Pad', async function () {
await agent.get(`${endPoint('getChatHistory')}&padID=${padID}`) await agent.get(`${endPoint('getChatHistory')}?padID=${padID}`)
.set("authorization", await generateJWTToken())
.expect('Content-Type', /json/) .expect('Content-Type', /json/)
.expect(200) .expect(200)
.expect((res:any) => { .expect((res:any) => {

View file

@ -11,10 +11,9 @@ import {MapArrayType} from "../../../../node/types/MapType";
const common = require('../../common'); const common = require('../../common');
let agent:any; let agent:any;
const apiKey = common.apiKey;
const apiVersion = 1; const apiVersion = 1;
const endPoint = (point: string, version?:string) => `/api/${version || apiVersion}/${point}?apikey=${apiKey}`; const endPoint = (point: string, version?:string) => `/api/${version || apiVersion}/${point}`;
const testImports:MapArrayType<any> = { const testImports:MapArrayType<any> = {
'malformed': { 'malformed': {
@ -243,29 +242,33 @@ describe(__filename, function () {
} }
it('createPad', async function () { it('createPad', async function () {
const res = await agent.get(`${endPoint('createPad')}&padID=${testPadId}`) const res = await agent.get(`${endPoint('createPad')}?padID=${testPadId}`)
.set("authorization", await common.generateJWTToken())
.expect(200) .expect(200)
.expect('Content-Type', /json/); .expect('Content-Type', /json/);
assert.equal(res.body.code, 0); assert.equal(res.body.code, 0);
}); });
it('setHTML', async function () { it('setHTML', async function () {
const res = await agent.get(`${endPoint('setHTML')}&padID=${testPadId}` + const res = await agent.get(`${endPoint('setHTML')}?padID=${testPadId}` +
`&html=${encodeURIComponent(test.input)}`) `&html=${encodeURIComponent(test.input)}`)
.set("authorization", await common.generateJWTToken())
.expect(200) .expect(200)
.expect('Content-Type', /json/); .expect('Content-Type', /json/);
assert.equal(res.body.code, 0); assert.equal(res.body.code, 0);
}); });
it('getHTML', async function () { it('getHTML', async function () {
const res = await agent.get(`${endPoint('getHTML')}&padID=${testPadId}`) const res = await agent.get(`${endPoint('getHTML')}?padID=${testPadId}`)
.set("authorization", await common.generateJWTToken())
.expect(200) .expect(200)
.expect('Content-Type', /json/); .expect('Content-Type', /json/);
assert.equal(res.body.data.html, test.wantHTML); assert.equal(res.body.data.html, test.wantHTML);
}); });
it('getText', async function () { it('getText', async function () {
const res = await agent.get(`${endPoint('getText')}&padID=${testPadId}`) const res = await agent.get(`${endPoint('getText')}?padID=${testPadId}`)
.set("authorization", await common.generateJWTToken())
.expect(200) .expect(200)
.expect('Content-Type', /json/); .expect('Content-Type', /json/);
assert.equal(res.body.data.text, test.wantText); assert.equal(res.body.data.text, test.wantText);

View file

@ -5,6 +5,8 @@
*/ */
import {MapArrayType} from "../../../../node/types/MapType"; import {MapArrayType} from "../../../../node/types/MapType";
import {SuperTestStatic} from "supertest";
import TestAgent from "supertest/lib/agent";
const assert = require('assert').strict; const assert = require('assert').strict;
const common = require('../../common'); const common = require('../../common');
@ -21,8 +23,7 @@ const wordXDoc = fs.readFileSync(`${__dirname}/test.docx`);
const odtDoc = fs.readFileSync(`${__dirname}/test.odt`); const odtDoc = fs.readFileSync(`${__dirname}/test.odt`);
const pdfDoc = fs.readFileSync(`${__dirname}/test.pdf`); const pdfDoc = fs.readFileSync(`${__dirname}/test.pdf`);
let agent:any; let agent: TestAgent;
const apiKey = common.apiKey;
const apiVersion = 1; const apiVersion = 1;
const testPadId = makeid(); const testPadId = makeid();
const testPadIdEnc = encodeURIComponent(testPadId); const testPadIdEnc = encodeURIComponent(testPadId);
@ -41,6 +42,7 @@ describe(__filename, function () {
describe('Connectivity', function () { describe('Connectivity', function () {
it('can connect', async function () { it('can connect', async function () {
await agent.get('/api/') await agent.get('/api/')
.set("authorization", await common.generateJWTToken())
.expect(200) .expect(200)
.expect('Content-Type', /json/); .expect('Content-Type', /json/);
}); });
@ -49,6 +51,7 @@ describe(__filename, function () {
describe('API Versioning', function () { describe('API Versioning', function () {
it('finds the version tag', async function () { it('finds the version tag', async function () {
await agent.get('/api/') await agent.get('/api/')
.set("authorization", await common.generateJWTToken())
.expect(200) .expect(200)
.expect((res:any) => assert(res.body.currentVersion)); .expect((res:any) => assert(res.body.currentVersion));
}); });
@ -103,14 +106,17 @@ describe(__filename, function () {
}); });
it('creates a new Pad, imports content to it, checks that content', async function () { it('creates a new Pad, imports content to it, checks that content', async function () {
await agent.get(`${endPoint('createPad')}&padID=${testPadId}`) await agent.get(`${endPoint('createPad')}?padID=${testPadId}`)
.set("authorization", await common.generateJWTToken())
.expect(200) .expect(200)
.expect('Content-Type', /json/) .expect('Content-Type', /json/)
.expect((res:any) => assert.equal(res.body.code, 0)); .expect((res:any) => assert.equal(res.body.code, 0));
await agent.post(`/p/${testPadId}/import`) await agent.post(`/p/${testPadId}/import`)
.set("authorization", await common.generateJWTToken())
.attach('file', padText, {filename: '/test.txt', contentType: 'text/plain'}) .attach('file', padText, {filename: '/test.txt', contentType: 'text/plain'})
.expect(200); .expect(200);
await agent.get(`${endPoint('getText')}&padID=${testPadId}`) await agent.get(`${endPoint('getText')}?padID=${testPadId}`)
.set("authorization", await common.generateJWTToken())
.expect(200) .expect(200)
.expect((res:any) => assert.equal(res.body.data.text, padText.toString())); .expect((res:any) => assert.equal(res.body.data.text, padText.toString()));
}); });
@ -122,9 +128,11 @@ describe(__filename, function () {
beforeEach(async function () { beforeEach(async function () {
if (readOnlyId != null) return; if (readOnlyId != null) return;
await agent.post(`/p/${testPadId}/import`) await agent.post(`/p/${testPadId}/import`)
.set("authorization", await common.generateJWTToken())
.attach('file', padText, {filename: '/test.txt', contentType: 'text/plain'}) .attach('file', padText, {filename: '/test.txt', contentType: 'text/plain'})
.expect(200); .expect(200);
const res = await agent.get(`${endPoint('getReadOnlyID')}&padID=${testPadId}`) const res = await agent.get(`${endPoint('getReadOnlyID')}?padID=${testPadId}`)
.set("authorization", await common.generateJWTToken())
.expect(200) .expect(200)
.expect('Content-Type', /json/) .expect('Content-Type', /json/)
.expect((res:any) => assert.equal(res.body.code, 0)); .expect((res:any) => assert.equal(res.body.code, 0));
@ -145,7 +153,8 @@ describe(__filename, function () {
// This ought to be before(), but it must run after the top-level beforeEach() above. // This ought to be before(), but it must run after the top-level beforeEach() above.
beforeEach(async function () { beforeEach(async function () {
if (text != null) return; if (text != null) return;
let req = agent.get(`/p/${readOnlyId}/export/${exportType}`); let req = agent.get(`/p/${readOnlyId}/export/${exportType}`)
.set("authorization", await common.generateJWTToken());
if (authn) req = req.auth('user', 'user-password'); if (authn) req = req.auth('user', 'user-password');
const res = await req const res = await req
.expect(200) .expect(200)
@ -163,6 +172,7 @@ describe(__filename, function () {
it('re-import to read-only pad ID gives 403 forbidden', async function () { it('re-import to read-only pad ID gives 403 forbidden', async function () {
let req = agent.post(`/p/${readOnlyId}/import`) let req = agent.post(`/p/${readOnlyId}/import`)
.set("authorization", await common.generateJWTToken())
.attach('file', Buffer.from(text), { .attach('file', Buffer.from(text), {
filename: `/test.${exportType}`, filename: `/test.${exportType}`,
contentType: 'text/plain', contentType: 'text/plain',
@ -175,6 +185,7 @@ describe(__filename, function () {
// The new pad ID must differ from testPadId because Etherpad refuses to import // The new pad ID must differ from testPadId because Etherpad refuses to import
// .etherpad files on top of a pad that already has edits. // .etherpad files on top of a pad that already has edits.
let req = agent.post(`/p/${testPadId}_import/import`) let req = agent.post(`/p/${testPadId}_import/import`)
.set("authorization", await common.generateJWTToken())
.attach('file', Buffer.from(text), { .attach('file', Buffer.from(text), {
filename: `/test.${exportType}`, filename: `/test.${exportType}`,
contentType: 'text/plain', contentType: 'text/plain',
@ -200,6 +211,7 @@ describe(__filename, function () {
// TODO: fix support for .doc files.. // TODO: fix support for .doc files..
it('Tries to import .doc that uses soffice or abiword', async function () { it('Tries to import .doc that uses soffice or abiword', async function () {
await agent.post(`/p/${testPadId}/import`) await agent.post(`/p/${testPadId}/import`)
.set("authorization", await common.generateJWTToken())
.attach('file', wordDoc, {filename: '/test.doc', contentType: 'application/msword'}) .attach('file', wordDoc, {filename: '/test.doc', contentType: 'application/msword'})
.expect(200) .expect(200)
.expect('Content-Type', /json/) .expect('Content-Type', /json/)
@ -212,6 +224,7 @@ describe(__filename, function () {
it('exports DOC', async function () { it('exports DOC', async function () {
await agent.get(`/p/${testPadId}/export/doc`) await agent.get(`/p/${testPadId}/export/doc`)
.set("authorization", await common.generateJWTToken())
.buffer(true).parse(superagent.parse['application/octet-stream']) .buffer(true).parse(superagent.parse['application/octet-stream'])
.expect(200) .expect(200)
.expect((res:any) => assert(res.body.length >= 9000)); .expect((res:any) => assert(res.body.length >= 9000));
@ -219,6 +232,7 @@ describe(__filename, function () {
it('Tries to import .docx that uses soffice or abiword', async function () { it('Tries to import .docx that uses soffice or abiword', async function () {
await agent.post(`/p/${testPadId}/import`) await agent.post(`/p/${testPadId}/import`)
.set("authorization", await common.generateJWTToken())
.attach('file', wordXDoc, { .attach('file', wordXDoc, {
filename: '/test.docx', filename: '/test.docx',
contentType: contentType:
@ -235,6 +249,7 @@ describe(__filename, function () {
it('exports DOC from imported DOCX', async function () { it('exports DOC from imported DOCX', async function () {
await agent.get(`/p/${testPadId}/export/doc`) await agent.get(`/p/${testPadId}/export/doc`)
.set("authorization", await common.generateJWTToken())
.buffer(true).parse(superagent.parse['application/octet-stream']) .buffer(true).parse(superagent.parse['application/octet-stream'])
.expect(200) .expect(200)
.expect((res:any) => assert(res.body.length >= 9100)); .expect((res:any) => assert(res.body.length >= 9100));
@ -242,6 +257,7 @@ describe(__filename, function () {
it('Tries to import .pdf that uses soffice or abiword', async function () { it('Tries to import .pdf that uses soffice or abiword', async function () {
await agent.post(`/p/${testPadId}/import`) await agent.post(`/p/${testPadId}/import`)
.set("authorization", await common.generateJWTToken())
.attach('file', pdfDoc, {filename: '/test.pdf', contentType: 'application/pdf'}) .attach('file', pdfDoc, {filename: '/test.pdf', contentType: 'application/pdf'})
.expect(200) .expect(200)
.expect('Content-Type', /json/) .expect('Content-Type', /json/)
@ -254,6 +270,7 @@ describe(__filename, function () {
it('exports PDF', async function () { it('exports PDF', async function () {
await agent.get(`/p/${testPadId}/export/pdf`) await agent.get(`/p/${testPadId}/export/pdf`)
.set("authorization", await common.generateJWTToken())
.buffer(true).parse(superagent.parse['application/octet-stream']) .buffer(true).parse(superagent.parse['application/octet-stream'])
.expect(200) .expect(200)
.expect((res:any) => assert(res.body.length >= 1000)); .expect((res:any) => assert(res.body.length >= 1000));
@ -261,6 +278,7 @@ describe(__filename, function () {
it('Tries to import .odt that uses soffice or abiword', async function () { it('Tries to import .odt that uses soffice or abiword', async function () {
await agent.post(`/p/${testPadId}/import`) await agent.post(`/p/${testPadId}/import`)
.set("authorization", await common.generateJWTToken())
.attach('file', odtDoc, {filename: '/test.odt', contentType: 'application/odt'}) .attach('file', odtDoc, {filename: '/test.odt', contentType: 'application/odt'})
.expect(200) .expect(200)
.expect('Content-Type', /json/) .expect('Content-Type', /json/)
@ -273,6 +291,7 @@ describe(__filename, function () {
it('exports ODT', async function () { it('exports ODT', async function () {
await agent.get(`/p/${testPadId}/export/odt`) await agent.get(`/p/${testPadId}/export/odt`)
.set("authorization", await common.generateJWTToken())
.buffer(true).parse(superagent.parse['application/octet-stream']) .buffer(true).parse(superagent.parse['application/octet-stream'])
.expect(200) .expect(200)
.expect((res:any) => assert(res.body.length >= 7000)); .expect((res:any) => assert(res.body.length >= 7000));
@ -282,6 +301,7 @@ describe(__filename, function () {
it('Tries to import .etherpad', async function () { it('Tries to import .etherpad', async function () {
this.timeout(3000); this.timeout(3000);
await agent.post(`/p/${testPadId}/import`) await agent.post(`/p/${testPadId}/import`)
.set("authorization", await common.generateJWTToken())
.attach('file', etherpadDoc, { .attach('file', etherpadDoc, {
filename: '/test.etherpad', filename: '/test.etherpad',
contentType: 'application/etherpad', contentType: 'application/etherpad',
@ -298,6 +318,7 @@ describe(__filename, function () {
it('exports Etherpad', async function () { it('exports Etherpad', async function () {
this.timeout(3000); this.timeout(3000);
await agent.get(`/p/${testPadId}/export/etherpad`) await agent.get(`/p/${testPadId}/export/etherpad`)
.set("authorization", await common.generateJWTToken())
.buffer(true).parse(superagent.parse.text) .buffer(true).parse(superagent.parse.text)
.expect(200) .expect(200)
.expect(/hello/); .expect(/hello/);
@ -306,6 +327,7 @@ describe(__filename, function () {
it('exports HTML for this Etherpad file', async function () { it('exports HTML for this Etherpad file', async function () {
this.timeout(3000); this.timeout(3000);
await agent.get(`/p/${testPadId}/export/html`) await agent.get(`/p/${testPadId}/export/html`)
.set("authorization", await common.generateJWTToken())
.expect(200) .expect(200)
.expect('content-type', 'text/html; charset=utf-8') .expect('content-type', 'text/html; charset=utf-8')
.expect(/<ul class="bullet"><li><ul class="bullet"><li>hello<\/ul><\/li><\/ul>/); .expect(/<ul class="bullet"><li><ul class="bullet"><li>hello<\/ul><\/li><\/ul>/);
@ -315,6 +337,7 @@ describe(__filename, function () {
this.timeout(3000); this.timeout(3000);
settings.allowUnknownFileEnds = false; settings.allowUnknownFileEnds = false;
await agent.post(`/p/${testPadId}/import`) await agent.post(`/p/${testPadId}/import`)
.set("authorization", await common.generateJWTToken())
.attach('file', padText, {filename: '/test.xasdasdxx', contentType: 'weirdness/jobby'}) .attach('file', padText, {filename: '/test.xasdasdxx', contentType: 'weirdness/jobby'})
.expect(400) .expect(400)
.expect('Content-Type', /json/) .expect('Content-Type', /json/)
@ -380,6 +403,8 @@ describe(__filename, function () {
// that a buggy makeGoodExport() doesn't cause checks to accidentally pass. // that a buggy makeGoodExport() doesn't cause checks to accidentally pass.
const records = makeGoodExport(); const records = makeGoodExport();
await deleteTestPad(); await deleteTestPad();
const importedPads = await importEtherpad(records)
console.log(importedPads)
await importEtherpad(records) await importEtherpad(records)
.expect(200) .expect(200)
.expect('Content-Type', /json/) .expect('Content-Type', /json/)
@ -389,6 +414,7 @@ describe(__filename, function () {
data: {directDatabaseAccess: true}, data: {directDatabaseAccess: true},
})); }));
await agent.get(`/p/${testPadId}/export/txt`) await agent.get(`/p/${testPadId}/export/txt`)
.set("authorization", await common.generateJWTToken())
.expect(200) .expect(200)
.buffer(true).parse(superagent.parse.text) .buffer(true).parse(superagent.parse.text)
.expect((res:any) => assert.match(res.text, /foo/)); .expect((res:any) => assert.match(res.text, /foo/));
@ -397,19 +423,19 @@ describe(__filename, function () {
it('missing rev', async function () { it('missing rev', async function () {
const records:MapArrayType<any> = makeGoodExport(); const records:MapArrayType<any> = makeGoodExport();
delete records['pad:testing:revs:0']; delete records['pad:testing:revs:0'];
await importEtherpad(records).expect(500); importEtherpad(records).expect(500);
}); });
it('bad changeset', async function () { it('bad changeset', async function () {
const records = makeGoodExport(); const records = makeGoodExport();
records['pad:testing:revs:0'].changeset = 'garbage'; records['pad:testing:revs:0'].changeset = 'garbage';
await importEtherpad(records).expect(500); importEtherpad(records).expect(500);
}); });
it('missing attrib in pool', async function () { it('missing attrib in pool', async function () {
const records = makeGoodExport(); const records = makeGoodExport();
records['pad:testing'].pool.nextNum++; records['pad:testing'].pool.nextNum++;
await importEtherpad(records).expect(500); (importEtherpad(records)).expect(500);
}); });
it('extra attrib in pool', async function () { it('extra attrib in pool', async function () {
@ -417,7 +443,7 @@ describe(__filename, function () {
const pool = records['pad:testing'].pool; const pool = records['pad:testing'].pool;
// @ts-ignore // @ts-ignore
pool.numToAttrib[pool.nextNum] = ['key', 'value']; pool.numToAttrib[pool.nextNum] = ['key', 'value'];
await importEtherpad(records).expect(500); (importEtherpad(records)).expect(500);
}); });
it('changeset refers to non-existent attrib', async function () { it('changeset refers to non-existent attrib', async function () {
@ -434,19 +460,19 @@ describe(__filename, function () {
text: 'asdffoo\n', text: 'asdffoo\n',
attribs: '*1+4|1+4', attribs: '*1+4|1+4',
}; };
await importEtherpad(records).expect(500); (importEtherpad(records)).expect(500);
}); });
it('pad atext does not match', async function () { it('pad atext does not match', async function () {
const records = makeGoodExport(); const records = makeGoodExport();
records['pad:testing'].atext.attribs = `*0${records['pad:testing'].atext.attribs}`; records['pad:testing'].atext.attribs = `*0${records['pad:testing'].atext.attribs}`;
await importEtherpad(records).expect(500); (importEtherpad(records)).expect(500);
}); });
it('missing chat message', async function () { it('missing chat message', async function () {
const records:MapArrayType<any> = makeGoodExport(); const records:MapArrayType<any> = makeGoodExport();
delete records['pad:testing:chat:0']; delete records['pad:testing:chat:0'];
await importEtherpad(records).expect(500); importEtherpad(records).expect(500);
}); });
}); });
@ -543,6 +569,7 @@ describe(__filename, function () {
data: {directDatabaseAccess: true}, data: {directDatabaseAccess: true},
})); }));
await agent.get(`/p/${testPadId}/export/txt`) await agent.get(`/p/${testPadId}/export/txt`)
.set("authorization", await common.generateJWTToken())
.expect(200) .expect(200)
.buffer(true).parse(superagent.parse.text) .buffer(true).parse(superagent.parse.text)
.expect((res:any) => assert.equal(res.text, 'oofoo\n')); .expect((res:any) => assert.equal(res.text, 'oofoo\n'));
@ -550,6 +577,7 @@ describe(__filename, function () {
it('txt request rev 1', async function () { it('txt request rev 1', async function () {
await agent.get(`/p/${testPadId}/1/export/txt`) await agent.get(`/p/${testPadId}/1/export/txt`)
.set("authorization", await common.generateJWTToken())
.expect(200) .expect(200)
.buffer(true).parse(superagent.parse.text) .buffer(true).parse(superagent.parse.text)
.expect((res:any) => assert.equal(res.text, 'ofoo\n')); .expect((res:any) => assert.equal(res.text, 'ofoo\n'));
@ -557,6 +585,7 @@ describe(__filename, function () {
it('txt request rev 2', async function () { it('txt request rev 2', async function () {
await agent.get(`/p/${testPadId}/2/export/txt`) await agent.get(`/p/${testPadId}/2/export/txt`)
.set("authorization", await common.generateJWTToken())
.expect(200) .expect(200)
.buffer(true).parse(superagent.parse.text) .buffer(true).parse(superagent.parse.text)
.expect((res:any) => assert.equal(res.text, 'oofoo\n')); .expect((res:any) => assert.equal(res.text, 'oofoo\n'));
@ -564,6 +593,7 @@ describe(__filename, function () {
it('txt request rev 1test returns rev 1', async function () { it('txt request rev 1test returns rev 1', async function () {
await agent.get(`/p/${testPadId}/1test/export/txt`) await agent.get(`/p/${testPadId}/1test/export/txt`)
.set("authorization", await common.generateJWTToken())
.expect(200) .expect(200)
.buffer(true).parse(superagent.parse.text) .buffer(true).parse(superagent.parse.text)
.expect((res:any) => assert.equal(res.text, 'ofoo\n')); .expect((res:any) => assert.equal(res.text, 'ofoo\n'));
@ -571,6 +601,7 @@ describe(__filename, function () {
it('txt request rev test1 is 403', async function () { it('txt request rev test1 is 403', async function () {
await agent.get(`/p/${testPadId}/test1/export/txt`) await agent.get(`/p/${testPadId}/test1/export/txt`)
.set("authorization", await common.generateJWTToken())
.expect(500) .expect(500)
.buffer(true).parse(superagent.parse.text) .buffer(true).parse(superagent.parse.text)
.expect((res:any) => assert.match(res.text, /rev is not a number/)); .expect((res:any) => assert.match(res.text, /rev is not a number/));
@ -578,6 +609,7 @@ describe(__filename, function () {
it('txt request rev 5 returns head rev', async function () { it('txt request rev 5 returns head rev', async function () {
await agent.get(`/p/${testPadId}/5/export/txt`) await agent.get(`/p/${testPadId}/5/export/txt`)
.set("authorization", await common.generateJWTToken())
.expect(200) .expect(200)
.buffer(true).parse(superagent.parse.text) .buffer(true).parse(superagent.parse.text)
.expect((res:any) => assert.equal(res.text, 'oofoo\n')); .expect((res:any) => assert.equal(res.text, 'oofoo\n'));
@ -585,6 +617,7 @@ describe(__filename, function () {
it('html request rev 1', async function () { it('html request rev 1', async function () {
await agent.get(`/p/${testPadId}/1/export/html`) await agent.get(`/p/${testPadId}/1/export/html`)
.set("authorization", await common.generateJWTToken())
.expect(200) .expect(200)
.buffer(true).parse(superagent.parse.text) .buffer(true).parse(superagent.parse.text)
.expect((res:any) => assert.match(res.text, /ofoo<br>/)); .expect((res:any) => assert.match(res.text, /ofoo<br>/));
@ -592,6 +625,7 @@ describe(__filename, function () {
it('html request rev 2', async function () { it('html request rev 2', async function () {
await agent.get(`/p/${testPadId}/2/export/html`) await agent.get(`/p/${testPadId}/2/export/html`)
.set("authorization", await common.generateJWTToken())
.expect(200) .expect(200)
.buffer(true).parse(superagent.parse.text) .buffer(true).parse(superagent.parse.text)
.expect((res:any) => assert.match(res.text, /oofoo<br>/)); .expect((res:any) => assert.match(res.text, /oofoo<br>/));
@ -599,6 +633,7 @@ describe(__filename, function () {
it('html request rev 1test returns rev 1', async function () { it('html request rev 1test returns rev 1', async function () {
await agent.get(`/p/${testPadId}/1test/export/html`) await agent.get(`/p/${testPadId}/1test/export/html`)
.set("authorization", await common.generateJWTToken())
.expect(200) .expect(200)
.buffer(true).parse(superagent.parse.text) .buffer(true).parse(superagent.parse.text)
.expect((res:any) => assert.match(res.text, /ofoo<br>/)); .expect((res:any) => assert.match(res.text, /ofoo<br>/));
@ -606,6 +641,7 @@ describe(__filename, function () {
it('html request rev test1 results in 500 response', async function () { it('html request rev test1 results in 500 response', async function () {
await agent.get(`/p/${testPadId}/test1/export/html`) await agent.get(`/p/${testPadId}/test1/export/html`)
.set("authorization", await common.generateJWTToken())
.expect(500) .expect(500)
.buffer(true).parse(superagent.parse.text) .buffer(true).parse(superagent.parse.text)
.expect((res:any) => assert.match(res.text, /rev is not a number/)); .expect((res:any) => assert.match(res.text, /rev is not a number/));
@ -613,6 +649,7 @@ describe(__filename, function () {
it('html request rev 5 returns head rev', async function () { it('html request rev 5 returns head rev', async function () {
await agent.get(`/p/${testPadId}/5/export/html`) await agent.get(`/p/${testPadId}/5/export/html`)
.set("authorization", await common.generateJWTToken())
.expect(200) .expect(200)
.buffer(true).parse(superagent.parse.text) .buffer(true).parse(superagent.parse.text)
.expect((res:any) => assert.match(res.text, /oofoo<br>/)); .expect((res:any) => assert.match(res.text, /oofoo<br>/));
@ -643,6 +680,7 @@ describe(__filename, function () {
it('!authn !exist -> create', async function () { it('!authn !exist -> create', async function () {
await agent.post(`/p/${testPadIdEnc}/import`) await agent.post(`/p/${testPadIdEnc}/import`)
.set("authorization", await common.generateJWTToken())
.attach('file', padText, {filename: '/test.txt', contentType: 'text/plain'}) .attach('file', padText, {filename: '/test.txt', contentType: 'text/plain'})
.expect(200); .expect(200);
assert(await padManager.doesPadExist(testPadId)); assert(await padManager.doesPadExist(testPadId));
@ -653,6 +691,7 @@ describe(__filename, function () {
it('!authn exist -> replace', async function () { it('!authn exist -> replace', async function () {
const pad = await createTestPad('before import'); const pad = await createTestPad('before import');
await agent.post(`/p/${testPadIdEnc}/import`) await agent.post(`/p/${testPadIdEnc}/import`)
.set("authorization", await common.generateJWTToken())
.attach('file', padText, {filename: '/test.txt', contentType: 'text/plain'}) .attach('file', padText, {filename: '/test.txt', contentType: 'text/plain'})
.expect(200); .expect(200);
assert(await padManager.doesPadExist(testPadId)); assert(await padManager.doesPadExist(testPadId));
@ -662,6 +701,7 @@ describe(__filename, function () {
it('authn anonymous !exist -> fail', async function () { it('authn anonymous !exist -> fail', async function () {
settings.requireAuthentication = true; settings.requireAuthentication = true;
await agent.post(`/p/${testPadIdEnc}/import`) await agent.post(`/p/${testPadIdEnc}/import`)
.set("authorization", await common.generateJWTToken())
.attach('file', padText, {filename: '/test.txt', contentType: 'text/plain'}) .attach('file', padText, {filename: '/test.txt', contentType: 'text/plain'})
.expect(401); .expect(401);
assert(!(await padManager.doesPadExist(testPadId))); assert(!(await padManager.doesPadExist(testPadId)));
@ -671,6 +711,7 @@ describe(__filename, function () {
settings.requireAuthentication = true; settings.requireAuthentication = true;
const pad = await createTestPad('before import\n'); const pad = await createTestPad('before import\n');
await agent.post(`/p/${testPadIdEnc}/import`) await agent.post(`/p/${testPadIdEnc}/import`)
.set("authorization", await common.generateJWTToken())
.attach('file', padText, {filename: '/test.txt', contentType: 'text/plain'}) .attach('file', padText, {filename: '/test.txt', contentType: 'text/plain'})
.expect(401); .expect(401);
assert.equal(pad.text(), 'before import\n'); assert.equal(pad.text(), 'before import\n');
@ -679,6 +720,7 @@ describe(__filename, function () {
it('authn user create !exist -> create', async function () { it('authn user create !exist -> create', async function () {
settings.requireAuthentication = true; settings.requireAuthentication = true;
await agent.post(`/p/${testPadIdEnc}/import`) await agent.post(`/p/${testPadIdEnc}/import`)
.set("authorization", await common.generateJWTToken())
.auth('user', 'user-password') .auth('user', 'user-password')
.attach('file', padText, {filename: '/test.txt', contentType: 'text/plain'}) .attach('file', padText, {filename: '/test.txt', contentType: 'text/plain'})
.expect(200); .expect(200);
@ -691,6 +733,7 @@ describe(__filename, function () {
settings.requireAuthentication = true; settings.requireAuthentication = true;
authorize = () => 'modify'; authorize = () => 'modify';
await agent.post(`/p/${testPadIdEnc}/import`) await agent.post(`/p/${testPadIdEnc}/import`)
.set("authorization", await common.generateJWTToken())
.auth('user', 'user-password') .auth('user', 'user-password')
.attach('file', padText, {filename: '/test.txt', contentType: 'text/plain'}) .attach('file', padText, {filename: '/test.txt', contentType: 'text/plain'})
.expect(403); .expect(403);
@ -701,6 +744,7 @@ describe(__filename, function () {
settings.requireAuthentication = true; settings.requireAuthentication = true;
authorize = () => 'readOnly'; authorize = () => 'readOnly';
await agent.post(`/p/${testPadIdEnc}/import`) await agent.post(`/p/${testPadIdEnc}/import`)
.set("authorization", await common.generateJWTToken())
.auth('user', 'user-password') .auth('user', 'user-password')
.attach('file', padText, {filename: '/test.txt', contentType: 'text/plain'}) .attach('file', padText, {filename: '/test.txt', contentType: 'text/plain'})
.expect(403); .expect(403);
@ -711,6 +755,7 @@ describe(__filename, function () {
settings.requireAuthentication = true; settings.requireAuthentication = true;
const pad = await createTestPad('before import\n'); const pad = await createTestPad('before import\n');
await agent.post(`/p/${testPadIdEnc}/import`) await agent.post(`/p/${testPadIdEnc}/import`)
.set("authorization", await common.generateJWTToken())
.auth('user', 'user-password') .auth('user', 'user-password')
.attach('file', padText, {filename: '/test.txt', contentType: 'text/plain'}) .attach('file', padText, {filename: '/test.txt', contentType: 'text/plain'})
.expect(200); .expect(200);
@ -722,6 +767,7 @@ describe(__filename, function () {
authorize = () => 'modify'; authorize = () => 'modify';
const pad = await createTestPad('before import\n'); const pad = await createTestPad('before import\n');
await agent.post(`/p/${testPadIdEnc}/import`) await agent.post(`/p/${testPadIdEnc}/import`)
.set("authorization", await common.generateJWTToken())
.auth('user', 'user-password') .auth('user', 'user-password')
.attach('file', padText, {filename: '/test.txt', contentType: 'text/plain'}) .attach('file', padText, {filename: '/test.txt', contentType: 'text/plain'})
.expect(200); .expect(200);
@ -733,6 +779,7 @@ describe(__filename, function () {
settings.requireAuthentication = true; settings.requireAuthentication = true;
authorize = () => 'readOnly'; authorize = () => 'readOnly';
await agent.post(`/p/${testPadIdEnc}/import`) await agent.post(`/p/${testPadIdEnc}/import`)
.set("authorization", await common.generateJWTToken())
.auth('user', 'user-password') .auth('user', 'user-password')
.attach('file', padText, {filename: '/test.txt', contentType: 'text/plain'}) .attach('file', padText, {filename: '/test.txt', contentType: 'text/plain'})
.expect(403); .expect(403);
@ -744,7 +791,7 @@ describe(__filename, function () {
const endPoint = (point: string, version?:string) => { const endPoint = (point: string, version?:string) => {
return `/api/${version || apiVersion}/${point}?apikey=${apiKey}`; return `/api/${version || apiVersion}/${point}`;
}; };
function makeid() { function makeid() {

View file

@ -8,10 +8,9 @@
const common = require('../../common'); const common = require('../../common');
let agent:any; let agent:any;
const apiKey = common.apiKey;
const apiVersion = '1.2.14'; const apiVersion = '1.2.14';
const endPoint = (point: string, version?: number) => `/api/${version || apiVersion}/${point}?apikey=${apiKey}`; const endPoint = (point: string, version?: number) => `/api/${version || apiVersion}/${point}`;
describe(__filename, function () { describe(__filename, function () {
before(async function () { agent = await common.init(); }); before(async function () { agent = await common.init(); });
@ -27,6 +26,7 @@ describe(__filename, function () {
describe('getStats', function () { describe('getStats', function () {
it('Gets the stats of a running instance', async function () { it('Gets the stats of a running instance', async function () {
await agent.get(endPoint('getStats')) await agent.get(endPoint('getStats'))
.set("Authorization", await common.generateJWTToken())
.expect((res:any) => { .expect((res:any) => {
if (res.body.code !== 0) throw new Error('getStats() failed'); if (res.body.code !== 0) throw new Error('getStats() failed');

View file

@ -21,7 +21,7 @@ const anotherPadId = makeid();
let lastEdited = ''; let lastEdited = '';
const text = generateLongText(); const text = generateLongText();
const endPoint = (point: string, version?: string) => `/api/${version || apiVersion}/${point}?apikey=${apiKey}`; const endPoint = (point: string, version?: string) => `/api/${version || apiVersion}/${point}`;
/* /*
* Html document with nested lists of different types, to test its import and * Html document with nested lists of different types, to test its import and
@ -63,7 +63,8 @@ describe(__filename, function () {
it('errors with invalid APIKey', async function () { it('errors with invalid APIKey', async function () {
// This is broken because Etherpad doesn't handle HTTP codes properly see #2343 // This is broken because Etherpad doesn't handle HTTP codes properly see #2343
// If your APIKey is password you deserve to fail all tests anyway // If your APIKey is password you deserve to fail all tests anyway
await agent.get(`/api/${apiVersion}/createPad?apikey=password&padID=test`) await agent.get(`/api/${apiVersion}/createPad?padID=test`)
.set("Authorization", (await common.generateJWTToken()).substring(0, 10))
.expect(401); .expect(401);
}); });
}); });
@ -113,20 +114,23 @@ describe(__filename, function () {
describe('Tests', function () { describe('Tests', function () {
it('deletes a Pad that does not exist', async function () { it('deletes a Pad that does not exist', async function () {
await agent.get(`${endPoint('deletePad')}&padID=${testPadId}`) await agent.get(`${endPoint('deletePad')}?padID=${testPadId}`)
.set("Authorization", (await common.generateJWTToken()))
.expect(200) // @TODO: we shouldn't expect 200 here since the pad may not exist .expect(200) // @TODO: we shouldn't expect 200 here since the pad may not exist
.expect('Content-Type', /json/); .expect('Content-Type', /json/);
}); });
it('creates a new Pad', async function () { it('creates a new Pad', async function () {
const res = await agent.get(`${endPoint('createPad')}&padID=${testPadId}`) const res = await agent.get(`${endPoint('createPad')}?padID=${testPadId}`)
.set("Authorization", (await common.generateJWTToken()))
.expect(200) .expect(200)
.expect('Content-Type', /json/); .expect('Content-Type', /json/);
assert.equal(res.body.code, 0); assert.equal(res.body.code, 0);
}); });
it('gets revision count of Pad', async function () { it('gets revision count of Pad', async function () {
const res = await agent.get(`${endPoint('getRevisionsCount')}&padID=${testPadId}`) const res = await agent.get(`${endPoint('getRevisionsCount')}?padID=${testPadId}`)
.set("Authorization", (await common.generateJWTToken()))
.expect(200) .expect(200)
.expect('Content-Type', /json/); .expect('Content-Type', /json/);
assert.equal(res.body.code, 0); assert.equal(res.body.code, 0);
@ -134,7 +138,8 @@ describe(__filename, function () {
}); });
it('gets saved revisions count of Pad', async function () { it('gets saved revisions count of Pad', async function () {
const res = await agent.get(`${endPoint('getSavedRevisionsCount')}&padID=${testPadId}`) const res = await agent.get(`${endPoint('getSavedRevisionsCount')}?padID=${testPadId}`)
.set("Authorization", (await common.generateJWTToken()))
.expect(200) .expect(200)
.expect('Content-Type', /json/); .expect('Content-Type', /json/);
assert.equal(res.body.code, 0); assert.equal(res.body.code, 0);
@ -142,7 +147,8 @@ describe(__filename, function () {
}); });
it('gets saved revision list of Pad', async function () { it('gets saved revision list of Pad', async function () {
const res = await agent.get(`${endPoint('listSavedRevisions')}&padID=${testPadId}`) const res = await agent.get(`${endPoint('listSavedRevisions')}?padID=${testPadId}`)
.set("Authorization", (await common.generateJWTToken()))
.expect(200) .expect(200)
.expect('Content-Type', /json/); .expect('Content-Type', /json/);
assert.equal(res.body.code, 0); assert.equal(res.body.code, 0);
@ -150,7 +156,8 @@ describe(__filename, function () {
}); });
it('get the HTML of Pad', async function () { it('get the HTML of Pad', async function () {
const res = await agent.get(`${endPoint('getHTML')}&padID=${testPadId}`) const res = await agent.get(`${endPoint('getHTML')}?padID=${testPadId}`)
.set("Authorization", (await common.generateJWTToken()))
.expect(200) .expect(200)
.expect('Content-Type', /json/); .expect('Content-Type', /json/);
assert(res.body.data.html.length > 1); assert(res.body.data.html.length > 1);
@ -158,13 +165,15 @@ describe(__filename, function () {
it('list all pads', async function () { it('list all pads', async function () {
const res = await agent.get(endPoint('listAllPads')) const res = await agent.get(endPoint('listAllPads'))
.set("Authorization", (await common.generateJWTToken()))
.expect(200) .expect(200)
.expect('Content-Type', /json/); .expect('Content-Type', /json/);
assert(res.body.data.padIDs.includes(testPadId)); assert(res.body.data.padIDs.includes(testPadId));
}); });
it('deletes the Pad', async function () { it('deletes the Pad', async function () {
const res = await agent.get(`${endPoint('deletePad')}&padID=${testPadId}`) const res = await agent.get(`${endPoint('deletePad')}?padID=${testPadId}`)
.set("Authorization", (await common.generateJWTToken()))
.expect(200) .expect(200)
.expect('Content-Type', /json/); .expect('Content-Type', /json/);
assert.equal(res.body.code, 0); assert.equal(res.body.code, 0);
@ -172,27 +181,31 @@ describe(__filename, function () {
it('list all pads again', async function () { it('list all pads again', async function () {
const res = await agent.get(endPoint('listAllPads')) const res = await agent.get(endPoint('listAllPads'))
.set("Authorization", (await common.generateJWTToken()))
.expect(200) .expect(200)
.expect('Content-Type', /json/); .expect('Content-Type', /json/);
assert(!res.body.data.padIDs.includes(testPadId)); assert(!res.body.data.padIDs.includes(testPadId));
}); });
it('get the HTML of a Pad -- Should return a failure', async function () { it('get the HTML of a Pad -- Should return a failure', async function () {
const res = await agent.get(`${endPoint('getHTML')}&padID=${testPadId}`) const res = await agent.get(`${endPoint('getHTML')}?padID=${testPadId}`)
.set("Authorization", (await common.generateJWTToken()))
.expect(200) .expect(200)
.expect('Content-Type', /json/); .expect('Content-Type', /json/);
assert.equal(res.body.code, 1); assert.equal(res.body.code, 1);
}); });
it('creates a new Pad with text', async function () { it('creates a new Pad with text', async function () {
const res = await agent.get(`${endPoint('createPad')}&padID=${testPadId}&text=testText`) const res = await agent.get(`${endPoint('createPad')}?padID=${testPadId}&text=testText`)
.set("Authorization", (await common.generateJWTToken()))
.expect(200) .expect(200)
.expect('Content-Type', /json/); .expect('Content-Type', /json/);
assert.equal(res.body.code, 0); assert.equal(res.body.code, 0);
}); });
it('gets the Pad text and expect it to be testText with trailing \\n', async function () { it('gets the Pad text and expect it to be testText with trailing \\n', async function () {
const res = await agent.get(`${endPoint('getText')}&padID=${testPadId}`) const res = await agent.get(`${endPoint('getText')}?padID=${testPadId}`)
.set("Authorization", (await common.generateJWTToken()))
.expect(200) .expect(200)
.expect('Content-Type', /json/); .expect('Content-Type', /json/);
assert.equal(res.body.data.text, 'testText\n'); assert.equal(res.body.data.text, 'testText\n');
@ -200,6 +213,7 @@ describe(__filename, function () {
it('set text', async function () { it('set text', async function () {
const res = await agent.post(endPoint('setText')) const res = await agent.post(endPoint('setText'))
.set("Authorization", (await common.generateJWTToken()))
.send({ .send({
padID: testPadId, padID: testPadId,
text: 'testTextTwo', text: 'testTextTwo',
@ -210,28 +224,32 @@ describe(__filename, function () {
}); });
it('gets the Pad text', async function () { it('gets the Pad text', async function () {
const res = await agent.get(`${endPoint('getText')}&padID=${testPadId}`) const res = await agent.get(`${endPoint('getText')}?padID=${testPadId}`)
.set("Authorization", (await common.generateJWTToken()))
.expect(200) .expect(200)
.expect('Content-Type', /json/); .expect('Content-Type', /json/);
assert.equal(res.body.data.text, 'testTextTwo\n'); assert.equal(res.body.data.text, 'testTextTwo\n');
}); });
it('gets Revision Count of a Pad', async function () { it('gets Revision Count of a Pad', async function () {
const res = await agent.get(`${endPoint('getRevisionsCount')}&padID=${testPadId}`) const res = await agent.get(`${endPoint('getRevisionsCount')}?padID=${testPadId}`)
.set("Authorization", (await common.generateJWTToken()))
.expect(200) .expect(200)
.expect('Content-Type', /json/); .expect('Content-Type', /json/);
assert.equal(res.body.data.revisions, 1); assert.equal(res.body.data.revisions, 1);
}); });
it('saves Revision', async function () { it('saves Revision', async function () {
const res = await agent.get(`${endPoint('saveRevision')}&padID=${testPadId}`) const res = await agent.get(`${endPoint('saveRevision')}?padID=${testPadId}`)
.set("Authorization", (await common.generateJWTToken()))
.expect(200) .expect(200)
.expect('Content-Type', /json/); .expect('Content-Type', /json/);
assert.equal(res.body.code, 0); assert.equal(res.body.code, 0);
}); });
it('gets saved revisions count of Pad again', async function () { it('gets saved revisions count of Pad again', async function () {
const res = await agent.get(`${endPoint('getSavedRevisionsCount')}&padID=${testPadId}`) const res = await agent.get(`${endPoint('getSavedRevisionsCount')}?padID=${testPadId}`)
.set("Authorization", (await common.generateJWTToken()))
.expect(200) .expect(200)
.expect('Content-Type', /json/); .expect('Content-Type', /json/);
assert.equal(res.body.code, 0); assert.equal(res.body.code, 0);
@ -239,7 +257,8 @@ describe(__filename, function () {
}); });
it('gets saved revision list of Pad again', async function () { it('gets saved revision list of Pad again', async function () {
const res = await agent.get(`${endPoint('listSavedRevisions')}&padID=${testPadId}`) const res = await agent.get(`${endPoint('listSavedRevisions')}?padID=${testPadId}`)
.set("Authorization", (await common.generateJWTToken()))
.expect(200) .expect(200)
.expect('Content-Type', /json/); .expect('Content-Type', /json/);
assert.equal(res.body.code, 0); assert.equal(res.body.code, 0);
@ -247,28 +266,32 @@ describe(__filename, function () {
}); });
it('gets User Count of a Pad', async function () { it('gets User Count of a Pad', async function () {
const res = await agent.get(`${endPoint('padUsersCount')}&padID=${testPadId}`) const res = await agent.get(`${endPoint('padUsersCount')}?padID=${testPadId}`)
.set("Authorization", (await common.generateJWTToken()))
.expect(200) .expect(200)
.expect('Content-Type', /json/); .expect('Content-Type', /json/);
assert.equal(res.body.data.padUsersCount, 0); assert.equal(res.body.data.padUsersCount, 0);
}); });
it('Gets the Read Only ID of a Pad', async function () { it('Gets the Read Only ID of a Pad', async function () {
const res = await agent.get(`${endPoint('getReadOnlyID')}&padID=${testPadId}`) const res = await agent.get(`${endPoint('getReadOnlyID')}?padID=${testPadId}`)
.set("Authorization", (await common.generateJWTToken()))
.expect(200) .expect(200)
.expect('Content-Type', /json/); .expect('Content-Type', /json/);
assert(res.body.data.readOnlyID); assert(res.body.data.readOnlyID);
}); });
it('Get Authors of the Pad', async function () { it('Get Authors of the Pad', async function () {
const res = await agent.get(`${endPoint('listAuthorsOfPad')}&padID=${testPadId}`) const res = await agent.get(`${endPoint('listAuthorsOfPad')}?padID=${testPadId}`)
.set("Authorization", (await common.generateJWTToken()))
.expect(200) .expect(200)
.expect('Content-Type', /json/); .expect('Content-Type', /json/);
assert.equal(res.body.data.authorIDs.length, 0); assert.equal(res.body.data.authorIDs.length, 0);
}); });
it('Get When Pad was left Edited', async function () { it('Get When Pad was left Edited', async function () {
const res = await agent.get(`${endPoint('getLastEdited')}&padID=${testPadId}`) const res = await agent.get(`${endPoint('getLastEdited')}?padID=${testPadId}`)
.set("Authorization", (await common.generateJWTToken()))
.expect(200) .expect(200)
.expect('Content-Type', /json/); .expect('Content-Type', /json/);
assert(res.body.data.lastEdited); assert(res.body.data.lastEdited);
@ -277,6 +300,7 @@ describe(__filename, function () {
it('set text again', async function () { it('set text again', async function () {
const res = await agent.post(endPoint('setText')) const res = await agent.post(endPoint('setText'))
.set("Authorization", (await common.generateJWTToken()))
.send({ .send({
padID: testPadId, padID: testPadId,
text: 'testTextThree', text: 'testTextThree',
@ -287,35 +311,40 @@ describe(__filename, function () {
}); });
it('Get When Pad was left Edited again', async function () { it('Get When Pad was left Edited again', async function () {
const res = await agent.get(`${endPoint('getLastEdited')}&padID=${testPadId}`) const res = await agent.get(`${endPoint('getLastEdited')}?padID=${testPadId}`)
.set("Authorization", (await common.generateJWTToken()))
.expect(200) .expect(200)
.expect('Content-Type', /json/); .expect('Content-Type', /json/);
assert(res.body.data.lastEdited > lastEdited); assert(res.body.data.lastEdited > lastEdited);
}); });
it('gets User Count of a Pad again', async function () { it('gets User Count of a Pad again', async function () {
const res = await agent.get(`${endPoint('padUsers')}&padID=${testPadId}`) const res = await agent.get(`${endPoint('padUsers')}?padID=${testPadId}`)
.set("Authorization", (await common.generateJWTToken()))
.expect(200) .expect(200)
.expect('Content-Type', /json/); .expect('Content-Type', /json/);
assert.equal(res.body.data.padUsers.length, 0); assert.equal(res.body.data.padUsers.length, 0);
}); });
it('deletes a Pad', async function () { it('deletes a Pad', async function () {
const res = await agent.get(`${endPoint('deletePad')}&padID=${testPadId}`) const res = await agent.get(`${endPoint('deletePad')}?padID=${testPadId}`)
.set("Authorization", (await common.generateJWTToken()))
.expect(200) .expect(200)
.expect('Content-Type', /json/); .expect('Content-Type', /json/);
assert.equal(res.body.code, 0); assert.equal(res.body.code, 0);
}); });
it('creates the Pad again', async function () { it('creates the Pad again', async function () {
const res = await agent.get(`${endPoint('createPad')}&padID=${testPadId}`) const res = await agent.get(`${endPoint('createPad')}?padID=${testPadId}`)
.set("Authorization", (await common.generateJWTToken()))
.expect(200) .expect(200)
.expect('Content-Type', /json/); .expect('Content-Type', /json/);
assert.equal(res.body.code, 0); assert.equal(res.body.code, 0);
}); });
it('Sets text on a pad Id', async function () { it('Sets text on a pad Id', async function () {
const res = await agent.post(`${endPoint('setText')}&padID=${testPadId}`) const res = await agent.post(`${endPoint('setText')}?padID=${testPadId}`)
.set("Authorization", (await common.generateJWTToken()))
.field({text}) .field({text})
.expect(200) .expect(200)
.expect('Content-Type', /json/); .expect('Content-Type', /json/);
@ -323,7 +352,8 @@ describe(__filename, function () {
}); });
it('Gets text on a pad Id', async function () { it('Gets text on a pad Id', async function () {
const res = await agent.get(`${endPoint('getText')}&padID=${testPadId}`) const res = await agent.get(`${endPoint('getText')}?padID=${testPadId}`)
.set("Authorization", (await common.generateJWTToken()))
.expect(200) .expect(200)
.expect('Content-Type', /json/); .expect('Content-Type', /json/);
assert.equal(res.body.code, 0); assert.equal(res.body.code, 0);
@ -331,7 +361,8 @@ describe(__filename, function () {
}); });
it('Sets text on a pad Id including an explicit newline', async function () { it('Sets text on a pad Id including an explicit newline', async function () {
const res = await agent.post(`${endPoint('setText')}&padID=${testPadId}`) const res = await agent.post(`${endPoint('setText')}?padID=${testPadId}`)
.set("Authorization", (await common.generateJWTToken()))
.field({text: `${text}\n`}) .field({text: `${text}\n`})
.expect(200) .expect(200)
.expect('Content-Type', /json/); .expect('Content-Type', /json/);
@ -339,7 +370,8 @@ describe(__filename, function () {
}); });
it("Gets text on a pad Id and doesn't have an excess newline", async function () { it("Gets text on a pad Id and doesn't have an excess newline", async function () {
const res = await agent.get(`${endPoint('getText')}&padID=${testPadId}`) const res = await agent.get(`${endPoint('getText')}?padID=${testPadId}`)
.set("Authorization", (await common.generateJWTToken()))
.expect(200) .expect(200)
.expect('Content-Type', /json/); .expect('Content-Type', /json/);
assert.equal(res.body.code, 0); assert.equal(res.body.code, 0);
@ -347,7 +379,8 @@ describe(__filename, function () {
}); });
it('Gets when pad was last edited', async function () { it('Gets when pad was last edited', async function () {
const res = await agent.get(`${endPoint('getLastEdited')}&padID=${testPadId}`) const res = await agent.get(`${endPoint('getLastEdited')}?padID=${testPadId}`)
.set("Authorization", (await common.generateJWTToken()))
.expect(200) .expect(200)
.expect('Content-Type', /json/); .expect('Content-Type', /json/);
assert.notEqual(res.body.lastEdited, 0); assert.notEqual(res.body.lastEdited, 0);
@ -355,14 +388,16 @@ describe(__filename, function () {
it('Move a Pad to a different Pad ID', async function () { it('Move a Pad to a different Pad ID', async function () {
const res = await agent.get( const res = await agent.get(
`${endPoint('movePad')}&sourceID=${testPadId}&destinationID=${newPadId}&force=true`) `${endPoint('movePad')}?sourceID=${testPadId}&destinationID=${newPadId}&force=true`)
.set("Authorization", (await common.generateJWTToken()))
.expect(200) .expect(200)
.expect('Content-Type', /json/); .expect('Content-Type', /json/);
assert.equal(res.body.code, 0); assert.equal(res.body.code, 0);
}); });
it('Gets text from new pad', async function () { it('Gets text from new pad', async function () {
const res = await agent.get(`${endPoint('getText')}&padID=${newPadId}`) const res = await agent.get(`${endPoint('getText')}?padID=${newPadId}`)
.set("Authorization", (await common.generateJWTToken()))
.expect(200) .expect(200)
.expect('Content-Type', /json/); .expect('Content-Type', /json/);
assert.equal(res.body.data.text, `${text}\n`); assert.equal(res.body.data.text, `${text}\n`);
@ -370,21 +405,24 @@ describe(__filename, function () {
it('Move pad back to original ID', async function () { it('Move pad back to original ID', async function () {
const res = await agent.get( const res = await agent.get(
`${endPoint('movePad')}&sourceID=${newPadId}&destinationID=${testPadId}&force=false`) `${endPoint('movePad')}?sourceID=${newPadId}&destinationID=${testPadId}&force=false`)
.set("Authorization", (await common.generateJWTToken()))
.expect(200) .expect(200)
.expect('Content-Type', /json/); .expect('Content-Type', /json/);
assert.equal(res.body.code, 0); assert.equal(res.body.code, 0);
}); });
it('Get text using original ID', async function () { it('Get text using original ID', async function () {
const res = await agent.get(`${endPoint('getText')}&padID=${testPadId}`) const res = await agent.get(`${endPoint('getText')}?padID=${testPadId}`)
.set("Authorization", (await common.generateJWTToken()))
.expect(200) .expect(200)
.expect('Content-Type', /json/); .expect('Content-Type', /json/);
assert.equal(res.body.data.text, `${text}\n`); assert.equal(res.body.data.text, `${text}\n`);
}); });
it('Get last edit of original ID', async function () { it('Get last edit of original ID', async function () {
const res = await agent.get(`${endPoint('getLastEdited')}&padID=${testPadId}`) const res = await agent.get(`${endPoint('getLastEdited')}?padID=${testPadId}`)
.set("Authorization", (await common.generateJWTToken()))
.expect(200) .expect(200)
.expect('Content-Type', /json/); .expect('Content-Type', /json/);
assert.notEqual(res.body.lastEdited, 0); assert.notEqual(res.body.lastEdited, 0);
@ -392,11 +430,13 @@ describe(__filename, function () {
it('Append text to a pad Id', async function () { it('Append text to a pad Id', async function () {
let res = await agent.get( let res = await agent.get(
`${endPoint('appendText', '1.2.13')}&padID=${testPadId}&text=hello`) `${endPoint('appendText', '1.2.13')}?padID=${testPadId}&text=hello`)
.set("Authorization", (await common.generateJWTToken()))
.expect(200) .expect(200)
.expect('Content-Type', /json/); .expect('Content-Type', /json/);
assert.equal(res.body.code, 0); assert.equal(res.body.code, 0);
res = await agent.get(`${endPoint('getText')}&padID=${testPadId}`) res = await agent.get(`${endPoint('getText')}?padID=${testPadId}`)
.set("Authorization", (await common.generateJWTToken()))
.expect(200) .expect(200)
.expect('Content-Type', /json/); .expect('Content-Type', /json/);
assert.equal(res.body.code, 0); assert.equal(res.body.code, 0);
@ -404,7 +444,8 @@ describe(__filename, function () {
}); });
it('getText of old revision', async function () { it('getText of old revision', async function () {
let res = await agent.get(`${endPoint('getRevisionsCount')}&padID=${testPadId}`) let res = await agent.get(`${endPoint('getRevisionsCount')}?padID=${testPadId}`)
.set("Authorization", (await common.generateJWTToken()))
.expect(200) .expect(200)
.expect('Content-Type', /json/); .expect('Content-Type', /json/);
assert.equal(res.body.code, 0); assert.equal(res.body.code, 0);
@ -412,7 +453,8 @@ describe(__filename, function () {
assert(rev != null); assert(rev != null);
assert(Number.isInteger(rev)); assert(Number.isInteger(rev));
assert(rev > 0); assert(rev > 0);
res = await agent.get(`${endPoint('getText')}&padID=${testPadId}&rev=${rev - 1}`) res = await agent.get(`${endPoint('getText')}?padID=${testPadId}&rev=${rev - 1}`)
.set("Authorization", (await common.generateJWTToken()))
.expect(200) .expect(200)
.expect('Content-Type', /json/); .expect('Content-Type', /json/);
assert.equal(res.body.code, 0); assert.equal(res.body.code, 0);
@ -422,6 +464,7 @@ describe(__filename, function () {
it('Sets the HTML of a Pad attempting to pass ugly HTML', async function () { it('Sets the HTML of a Pad attempting to pass ugly HTML', async function () {
const html = '<div><b>Hello HTML</title></head></div>'; const html = '<div><b>Hello HTML</title></head></div>';
const res = await agent.post(endPoint('setHTML')) const res = await agent.post(endPoint('setHTML'))
.set("Authorization", (await common.generateJWTToken()))
.send({ .send({
padID: testPadId, padID: testPadId,
html, html,
@ -433,6 +476,7 @@ describe(__filename, function () {
it('Pad with complex nested lists of different types', async function () { it('Pad with complex nested lists of different types', async function () {
let res = await agent.post(endPoint('setHTML')) let res = await agent.post(endPoint('setHTML'))
.set("Authorization", (await common.generateJWTToken()))
.send({ .send({
padID: testPadId, padID: testPadId,
html: ulHtml, html: ulHtml,
@ -440,7 +484,8 @@ describe(__filename, function () {
.expect(200) .expect(200)
.expect('Content-Type', /json/); .expect('Content-Type', /json/);
assert.equal(res.body.code, 0); assert.equal(res.body.code, 0);
res = await agent.get(`${endPoint('getHTML')}&padID=${testPadId}`) res = await agent.get(`${endPoint('getHTML')}?padID=${testPadId}`)
.set("Authorization", (await common.generateJWTToken()))
.expect(200) .expect(200)
.expect('Content-Type', /json/); .expect('Content-Type', /json/);
const receivedHtml = res.body.data.html.replace('<br></body>', '</body>').toLowerCase(); const receivedHtml = res.body.data.html.replace('<br></body>', '</body>').toLowerCase();
@ -448,11 +493,13 @@ describe(__filename, function () {
}); });
it('Pad with white space between list items', async function () { it('Pad with white space between list items', async function () {
let res = await agent.get(`${endPoint('setHTML')}&padID=${testPadId}&html=${ulSpaceHtml}`) let res = await agent.get(`${endPoint('setHTML')}?padID=${testPadId}&html=${ulSpaceHtml}`)
.set("Authorization", (await common.generateJWTToken()))
.expect(200) .expect(200)
.expect('Content-Type', /json/); .expect('Content-Type', /json/);
assert.equal(res.body.code, 0); assert.equal(res.body.code, 0);
res = await agent.get(`${endPoint('getHTML')}&padID=${testPadId}`) res = await agent.get(`${endPoint('getHTML')}?padID=${testPadId}`)
.set("Authorization", (await common.generateJWTToken()))
.expect(200) .expect(200)
.expect('Content-Type', /json/); .expect('Content-Type', /json/);
const receivedHtml = res.body.data.html.replace('<br></body>', '</body>').toLowerCase(); const receivedHtml = res.body.data.html.replace('<br></body>', '</body>').toLowerCase();
@ -461,7 +508,8 @@ describe(__filename, function () {
it('errors if pad can be created', async function () { it('errors if pad can be created', async function () {
await Promise.all(['/', '%23', '%3F', '%26'].map(async (badUrlChar) => { await Promise.all(['/', '%23', '%3F', '%26'].map(async (badUrlChar) => {
const res = await agent.get(`${endPoint('createPad')}&padID=${badUrlChar}`) const res = await agent.get(`${endPoint('createPad')}?padID=${badUrlChar}`)
.set("Authorization", (await common.generateJWTToken()))
.expect('Content-Type', /json/); .expect('Content-Type', /json/);
assert.equal(res.body.code, 1); assert.equal(res.body.code, 1);
})); }));
@ -469,49 +517,57 @@ describe(__filename, function () {
it('copies the content of a existent pad', async function () { it('copies the content of a existent pad', async function () {
const res = await agent.get( const res = await agent.get(
`${endPoint('copyPad')}&sourceID=${testPadId}&destinationID=${copiedPadId}&force=true`) `${endPoint('copyPad')}?sourceID=${testPadId}&destinationID=${copiedPadId}&force=true`)
.set("Authorization", (await common.generateJWTToken()))
.expect(200) .expect(200)
.expect('Content-Type', /json/); .expect('Content-Type', /json/);
assert.equal(res.body.code, 0); assert.equal(res.body.code, 0);
}); });
it('does not add an useless revision', async function () { it('does not add an useless revision', async function () {
let res = await agent.post(`${endPoint('setText')}&padID=${testPadId}`) let res = await agent.post(`${endPoint('setText')}?padID=${testPadId}`)
.set("Authorization", (await common.generateJWTToken()))
.field({text: 'identical text\n'}) .field({text: 'identical text\n'})
.expect(200) .expect(200)
.expect('Content-Type', /json/); .expect('Content-Type', /json/);
assert.equal(res.body.code, 0); assert.equal(res.body.code, 0);
res = await agent.get(`${endPoint('getText')}&padID=${testPadId}`) res = await agent.get(`${endPoint('getText')}?padID=${testPadId}`)
.set("Authorization", (await common.generateJWTToken()))
.expect(200) .expect(200)
.expect('Content-Type', /json/); .expect('Content-Type', /json/);
assert.equal(res.body.data.text, 'identical text\n'); assert.equal(res.body.data.text, 'identical text\n');
res = await agent.get(`${endPoint('getRevisionsCount')}&padID=${testPadId}`) res = await agent.get(`${endPoint('getRevisionsCount')}?padID=${testPadId}`)
.set("Authorization", (await common.generateJWTToken()))
.expect(200) .expect(200)
.expect('Content-Type', /json/); .expect('Content-Type', /json/);
const revCount = res.body.data.revisions; const revCount = res.body.data.revisions;
res = await agent.post(`${endPoint('setText')}&padID=${testPadId}`) res = await agent.post(`${endPoint('setText')}?padID=${testPadId}`)
.set("Authorization", (await common.generateJWTToken()))
.field({text: 'identical text\n'}) .field({text: 'identical text\n'})
.expect(200) .expect(200)
.expect('Content-Type', /json/); .expect('Content-Type', /json/);
assert.equal(res.body.code, 0); assert.equal(res.body.code, 0);
res = await agent.get(`${endPoint('getRevisionsCount')}&padID=${testPadId}`) res = await agent.get(`${endPoint('getRevisionsCount')}?padID=${testPadId}`)
.set("Authorization", (await common.generateJWTToken()))
.expect(200) .expect(200)
.expect('Content-Type', /json/); .expect('Content-Type', /json/);
assert.equal(res.body.data.revisions, revCount); assert.equal(res.body.data.revisions, revCount);
}); });
it('creates a new Pad with empty text', async function () { it('creates a new Pad with empty text', async function () {
await agent.get(`${endPoint('createPad')}&padID=${anotherPadId}&text=`) await agent.get(`${endPoint('createPad')}?padID=${anotherPadId}&text=`)
.set("Authorization", (await common.generateJWTToken()))
.expect('Content-Type', /json/) .expect('Content-Type', /json/)
.expect(200) .expect(200)
.expect((res:any) => { .expect((res:any) => {
assert.equal(res.body.code, 0, 'Unable to create new Pad'); assert.equal(res.body.code, 0, 'Unable to create new Pad');
}); });
await agent.get(`${endPoint('getText')}&padID=${anotherPadId}`) await agent.get(`${endPoint('getText')}?padID=${anotherPadId}`)
.set("Authorization", (await common.generateJWTToken()))
.expect('Content-Type', /json/) .expect('Content-Type', /json/)
.expect(200) .expect(200)
.expect((res:any) => { .expect((res:any) => {
@ -521,7 +577,8 @@ describe(__filename, function () {
}); });
it('deletes with empty text', async function () { it('deletes with empty text', async function () {
await agent.get(`${endPoint('deletePad')}&padID=${anotherPadId}`) await agent.get(`${endPoint('deletePad')}?padID=${anotherPadId}`)
.set("Authorization", (await common.generateJWTToken()))
.expect('Content-Type', /json/) .expect('Content-Type', /json/)
.expect(200) .expect(200)
.expect((res: any) => { .expect((res: any) => {
@ -543,8 +600,9 @@ describe(__filename, function () {
}); });
it('returns a successful response', async function () { it('returns a successful response', async function () {
const res = await agent.get(`${endPoint('copyPadWithoutHistory')}&sourceID=${sourcePadId}` + const res = await agent.get(`${endPoint('copyPadWithoutHistory')}?sourceID=${sourcePadId}` +
`&destinationID=${newPad}&force=false`) `&destinationID=${newPad}&force=false`)
.set("Authorization", (await common.generateJWTToken()))
.expect(200) .expect(200)
.expect('Content-Type', /json/); .expect('Content-Type', /json/);
assert.equal(res.body.code, 0); assert.equal(res.body.code, 0);
@ -552,10 +610,12 @@ describe(__filename, function () {
// this test validates if the source pad's text and attributes are kept // this test validates if the source pad's text and attributes are kept
it('creates a new pad with the same content as the source pad', async function () { it('creates a new pad with the same content as the source pad', async function () {
let res = await agent.get(`${endPoint('copyPadWithoutHistory')}&sourceID=${sourcePadId}` + let res = await agent.get(`${endPoint('copyPadWithoutHistory')}?sourceID=${sourcePadId}` +
`&destinationID=${newPad}&force=false`); `&destinationID=${newPad}&force=false`)
.set("Authorization", (await common.generateJWTToken()));
assert.equal(res.body.code, 0); assert.equal(res.body.code, 0);
res = await agent.get(`${endPoint('getHTML')}&padID=${newPad}`) res = await agent.get(`${endPoint('getHTML')}?padID=${newPad}`)
.set("Authorization", (await common.generateJWTToken()))
.expect(200); .expect(200);
const receivedHtml = res.body.data.html.replace('<br><br></body>', '</body>').toLowerCase(); const receivedHtml = res.body.data.html.replace('<br><br></body>', '</body>').toLowerCase();
assert.equal(receivedHtml, expectedHtml); assert.equal(receivedHtml, expectedHtml);
@ -564,8 +624,9 @@ describe(__filename, function () {
it('copying to a non-existent group throws an error', async function () { it('copying to a non-existent group throws an error', async function () {
const padWithNonExistentGroup = `notExistentGroup$${newPad}`; const padWithNonExistentGroup = `notExistentGroup$${newPad}`;
const res = await agent.get(`${endPoint('copyPadWithoutHistory')}` + const res = await agent.get(`${endPoint('copyPadWithoutHistory')}` +
`&sourceID=${sourcePadId}` + `?sourceID=${sourcePadId}` +
`&destinationID=${padWithNonExistentGroup}&force=true`) `&destinationID=${padWithNonExistentGroup}&force=true`)
.set("Authorization", (await common.generateJWTToken()))
.expect(200); .expect(200);
assert.equal(res.body.code, 1); assert.equal(res.body.code, 1);
}); });
@ -577,16 +638,18 @@ describe(__filename, function () {
it('force=false fails', async function () { it('force=false fails', async function () {
const res = await agent.get(`${endPoint('copyPadWithoutHistory')}` + const res = await agent.get(`${endPoint('copyPadWithoutHistory')}` +
`&sourceID=${sourcePadId}` + `?sourceID=${sourcePadId}` +
`&destinationID=${newPad}&force=false`) `&destinationID=${newPad}&force=false`)
.set("Authorization", (await common.generateJWTToken()))
.expect(200); .expect(200);
assert.equal(res.body.code, 1); assert.equal(res.body.code, 1);
}); });
it('force=true succeeds', async function () { it('force=true succeeds', async function () {
const res = await agent.get(`${endPoint('copyPadWithoutHistory')}` + const res = await agent.get(`${endPoint('copyPadWithoutHistory')}` +
`&sourceID=${sourcePadId}` + `?sourceID=${sourcePadId}` +
`&destinationID=${newPad}&force=true`) `&destinationID=${newPad}&force=true`)
.set("Authorization", (await common.generateJWTToken()))
.expect(200); .expect(200);
assert.equal(res.body.code, 0); assert.equal(res.body.code, 0);
}); });
@ -613,7 +676,8 @@ describe(__filename, function () {
// state between the two attribute pools caused corruption. // state between the two attribute pools caused corruption.
const getHtml = async (padId:string) => { const getHtml = async (padId:string) => {
const res = await agent.get(`${endPoint('getHTML')}&padID=${padId}`) const res = await agent.get(`${endPoint('getHTML')}?padID=${padId}`)
.set("Authorization", (await common.generateJWTToken()))
.expect(200) .expect(200)
.expect('Content-Type', /json/); .expect('Content-Type', /json/);
assert.equal(res.body.code, 0); assert.equal(res.body.code, 0);
@ -622,6 +686,7 @@ describe(__filename, function () {
const setBody = async (padId: string, bodyHtml: string) => { const setBody = async (padId: string, bodyHtml: string) => {
await agent.post(endPoint('setHTML')) await agent.post(endPoint('setHTML'))
.set("Authorization", (await common.generateJWTToken()))
.send({padID: padId, html: `<!DOCTYPE HTML><html><body>${bodyHtml}</body></html>`}) .send({padID: padId, html: `<!DOCTYPE HTML><html><body>${bodyHtml}</body></html>`})
.expect(200) .expect(200)
.expect('Content-Type', /json/) .expect('Content-Type', /json/)
@ -631,8 +696,9 @@ describe(__filename, function () {
const origHtml = await getHtml(sourcePadId); const origHtml = await getHtml(sourcePadId);
assert.doesNotMatch(origHtml, /<strong>/); assert.doesNotMatch(origHtml, /<strong>/);
assert.doesNotMatch(origHtml, /<em>/); assert.doesNotMatch(origHtml, /<em>/);
await agent.get(`${endPoint('copyPadWithoutHistory')}&sourceID=${sourcePadId}` + await agent.get(`${endPoint('copyPadWithoutHistory')}?sourceID=${sourcePadId}` +
`&destinationID=${newPad}&force=false`) `&destinationID=${newPad}&force=false`)
.set("Authorization", (await common.generateJWTToken()))
.expect(200) .expect(200)
.expect('Content-Type', /json/) .expect('Content-Type', /json/)
.expect((res:any) => assert.equal(res.body.code, 0)); .expect((res:any) => assert.equal(res.body.code, 0));
@ -672,8 +738,10 @@ describe(__filename, function () {
*/ */
const createNewPadWithHtml = async (padId: string, html: string) => { const createNewPadWithHtml = async (padId: string, html: string) => {
await agent.get(`${endPoint('createPad')}&padID=${padId}`); await agent.get(`${endPoint('createPad')}?padID=${padId}`)
.set("Authorization", (await common.generateJWTToken()));
await agent.post(endPoint('setHTML')) await agent.post(endPoint('setHTML'))
.set("Authorization", (await common.generateJWTToken()))
.send({ .send({
padID: padId, padID: padId,
html, html,

View file

@ -21,6 +21,7 @@ describe(__filename, function () {
...(authorId == null ? {} : {authorId}), ...(authorId == null ? {} : {authorId}),
})); }));
const res = await agent.get(`/api/${v}/restoreRevision?${p}`) const res = await agent.get(`/api/${v}/restoreRevision?${p}`)
.set("Authorization", (await common.generateJWTToken()))
.expect(200) .expect(200)
.expect('Content-Type', /json/); .expect('Content-Type', /json/);
assert.equal(res.body.code, 0); assert.equal(res.body.code, 0);

View file

@ -1,25 +1,33 @@
'use strict'; 'use strict';
import {agent, generateJWTToken, init, logger} from "../../common";
import TestAgent from "supertest/lib/agent";
import supertest from "supertest";
const assert = require('assert').strict; const assert = require('assert').strict;
const common = require('../../common');
const db = require('../../../../node/db/DB'); const db = require('../../../../node/db/DB');
let agent:any;
const apiKey = common.apiKey;
let apiVersion = 1; let apiVersion = 1;
let groupID = ''; let groupID = '';
let authorID = ''; let authorID = '';
let sessionID = ''; let sessionID = '';
let padID = makeid(); let padID = makeid();
const endPoint = (point:string) => `/api/${apiVersion}/${point}?apikey=${apiKey}`; const endPoint = (point:string) => {
return `/api/${apiVersion}/${point}`;
}
let preparedAgent: TestAgent<supertest.Test>
describe(__filename, function () { describe(__filename, function () {
before(async function () { agent = await common.init(); }); before(async function () {
preparedAgent = await init();
});
describe('API Versioning', function () { describe('API Versioning', function () {
it('errors if can not connect', async function () { it('errors if can not connect', async function () {
await agent.get('/api/') await agent!.get('/api/')
.set('Accept', 'application/json')
.expect(200) .expect(200)
.expect((res:any) => { .expect((res:any) => {
assert(res.body.currentVersion); assert(res.body.currentVersion);
@ -60,7 +68,8 @@ describe(__filename, function () {
describe('API: Group creation and deletion', function () { describe('API: Group creation and deletion', function () {
it('createGroup', async function () { it('createGroup', async function () {
await agent.get(endPoint('createGroup')) await agent!.get(endPoint('createGroup'))
.set("Authorization", await generateJWTToken())
.expect(200) .expect(200)
.expect('Content-Type', /json/) .expect('Content-Type', /json/)
.expect((res:any) => { .expect((res:any) => {
@ -71,7 +80,8 @@ describe(__filename, function () {
}); });
it('listSessionsOfGroup for empty group', async function () { it('listSessionsOfGroup for empty group', async function () {
await agent.get(`${endPoint('listSessionsOfGroup')}&groupID=${groupID}`) await agent!.get(`${endPoint('listSessionsOfGroup')}?groupID=${groupID}`)
.set("Authorization", await generateJWTToken())
.expect(200) .expect(200)
.expect('Content-Type', /json/) .expect('Content-Type', /json/)
.expect((res:any) => { .expect((res:any) => {
@ -81,7 +91,9 @@ describe(__filename, function () {
}); });
it('deleteGroup', async function () { it('deleteGroup', async function () {
await agent.get(`${endPoint('deleteGroup')}&groupID=${groupID}`) await agent!
.get(`${endPoint('deleteGroup')}?groupID=${groupID}`)
.set("Authorization", await generateJWTToken())
.expect(200) .expect(200)
.expect('Content-Type', /json/) .expect('Content-Type', /json/)
.expect((res:any) => { .expect((res:any) => {
@ -92,7 +104,8 @@ describe(__filename, function () {
it('createGroupIfNotExistsFor', async function () { it('createGroupIfNotExistsFor', async function () {
const mapper = makeid(); const mapper = makeid();
let groupId: string; let groupId: string;
await agent.get(`${endPoint('createGroupIfNotExistsFor')}&groupMapper=${mapper}`) await preparedAgent.get(`${endPoint('createGroupIfNotExistsFor')}?groupMapper=${mapper}`)
.set("Authorization", await generateJWTToken())
.expect(200) .expect(200)
.expect('Content-Type', /json/) .expect('Content-Type', /json/)
.expect((res:any) => { .expect((res:any) => {
@ -101,7 +114,8 @@ describe(__filename, function () {
assert(groupId); assert(groupId);
}); });
// Passing the same mapper should return the same group ID. // Passing the same mapper should return the same group ID.
await agent.get(`${endPoint('createGroupIfNotExistsFor')}&groupMapper=${mapper}`) await preparedAgent.get(`${endPoint('createGroupIfNotExistsFor')}?groupMapper=${mapper}`)
.set("Authorization", await generateJWTToken())
.expect(200) .expect(200)
.expect('Content-Type', /json/) .expect('Content-Type', /json/)
.expect((res:any) => { .expect((res:any) => {
@ -110,7 +124,8 @@ describe(__filename, function () {
}); });
// Deleting the group should clean up the mapping. // Deleting the group should clean up the mapping.
assert.equal(await db.get(`mapper2group:${mapper}`), groupId!); assert.equal(await db.get(`mapper2group:${mapper}`), groupId!);
await agent.get(`${endPoint('deleteGroup')}&groupID=${groupId!}`) await preparedAgent.get(`${endPoint('deleteGroup')}?groupID=${groupId!}`)
.set("Authorization", await generateJWTToken())
.expect(200) .expect(200)
.expect('Content-Type', /json/) .expect('Content-Type', /json/)
.expect((res:any) => { .expect((res:any) => {
@ -122,7 +137,8 @@ describe(__filename, function () {
// Test coverage for https://github.com/ether/etherpad-lite/issues/4227 // Test coverage for https://github.com/ether/etherpad-lite/issues/4227
// Creates a group, creates 2 sessions, 2 pads and then deletes the group. // Creates a group, creates 2 sessions, 2 pads and then deletes the group.
it('createGroup', async function () { it('createGroup', async function () {
await agent.get(endPoint('createGroup')) await preparedAgent.get(endPoint('createGroup'))
.set("Authorization", await generateJWTToken())
.expect(200) .expect(200)
.expect('Content-Type', /json/) .expect('Content-Type', /json/)
.expect((res:any) => { .expect((res:any) => {
@ -133,7 +149,8 @@ describe(__filename, function () {
}); });
it('createAuthor', async function () { it('createAuthor', async function () {
await agent.get(endPoint('createAuthor')) await preparedAgent.get(endPoint('createAuthor'))
.set("Authorization", await generateJWTToken())
.expect(200) .expect(200)
.expect('Content-Type', /json/) .expect('Content-Type', /json/)
.expect((res:any) => { .expect((res:any) => {
@ -144,8 +161,9 @@ describe(__filename, function () {
}); });
it('createSession', async function () { it('createSession', async function () {
await agent.get(`${endPoint('createSession')}&authorID=${authorID}&groupID=${groupID}` + await preparedAgent.get(`${endPoint('createSession')}?authorID=${authorID}&groupID=${groupID}` +
'&validUntil=999999999999') '&validUntil=999999999999')
.set("Authorization", await generateJWTToken())
.expect(200) .expect(200)
.expect('Content-Type', /json/) .expect('Content-Type', /json/)
.expect((res:any) => { .expect((res:any) => {
@ -156,8 +174,9 @@ describe(__filename, function () {
}); });
it('createSession', async function () { it('createSession', async function () {
await agent.get(`${endPoint('createSession')}&authorID=${authorID}&groupID=${groupID}` + await preparedAgent.get(`${endPoint('createSession')}?authorID=${authorID}&groupID=${groupID}` +
'&validUntil=999999999999') '&validUntil=999999999999')
.set("Authorization", await generateJWTToken())
.expect(200) .expect(200)
.expect('Content-Type', /json/) .expect('Content-Type', /json/)
.expect((res:any) => { .expect((res:any) => {
@ -168,7 +187,8 @@ describe(__filename, function () {
}); });
it('createGroupPad', async function () { it('createGroupPad', async function () {
await agent.get(`${endPoint('createGroupPad')}&groupID=${groupID}&padName=x1234567`) await preparedAgent.get(`${endPoint('createGroupPad')}?groupID=${groupID}&padName=x1234567`)
.set("Authorization", await generateJWTToken())
.expect(200) .expect(200)
.expect('Content-Type', /json/) .expect('Content-Type', /json/)
.expect((res:any) => { .expect((res:any) => {
@ -177,7 +197,8 @@ describe(__filename, function () {
}); });
it('createGroupPad', async function () { it('createGroupPad', async function () {
await agent.get(`${endPoint('createGroupPad')}&groupID=${groupID}&padName=x12345678`) await preparedAgent.get(`${endPoint('createGroupPad')}?groupID=${groupID}&padName=x12345678`)
.set("Authorization", await generateJWTToken())
.expect(200) .expect(200)
.expect('Content-Type', /json/) .expect('Content-Type', /json/)
.expect((res:any) => { .expect((res:any) => {
@ -186,7 +207,8 @@ describe(__filename, function () {
}); });
it('deleteGroup', async function () { it('deleteGroup', async function () {
await agent.get(`${endPoint('deleteGroup')}&groupID=${groupID}`) await preparedAgent.get(`${endPoint('deleteGroup')}?groupID=${groupID}`)
.set("Authorization", await generateJWTToken())
.expect(200) .expect(200)
.expect('Content-Type', /json/) .expect('Content-Type', /json/)
.expect((res:any) => { .expect((res:any) => {
@ -198,7 +220,8 @@ describe(__filename, function () {
describe('API: Author creation', function () { describe('API: Author creation', function () {
it('createGroup', async function () { it('createGroup', async function () {
await agent.get(endPoint('createGroup')) await preparedAgent.get(endPoint('createGroup'))
.set("Authorization", await generateJWTToken())
.expect(200) .expect(200)
.expect('Content-Type', /json/) .expect('Content-Type', /json/)
.expect((res:any) => { .expect((res:any) => {
@ -209,7 +232,8 @@ describe(__filename, function () {
}); });
it('createAuthor', async function () { it('createAuthor', async function () {
await agent.get(endPoint('createAuthor')) await preparedAgent.get(endPoint('createAuthor'))
.set("Authorization", await generateJWTToken())
.expect(200) .expect(200)
.expect('Content-Type', /json/) .expect('Content-Type', /json/)
.expect((res:any) => { .expect((res:any) => {
@ -219,7 +243,8 @@ describe(__filename, function () {
}); });
it('createAuthor with name', async function () { it('createAuthor with name', async function () {
await agent.get(`${endPoint('createAuthor')}&name=john`) await preparedAgent.get(`${endPoint('createAuthor')}?name=john`)
.set("Authorization", await generateJWTToken())
.expect(200) .expect(200)
.expect('Content-Type', /json/) .expect('Content-Type', /json/)
.expect((res:any) => { .expect((res:any) => {
@ -230,7 +255,8 @@ describe(__filename, function () {
}); });
it('createAuthorIfNotExistsFor', async function () { it('createAuthorIfNotExistsFor', async function () {
await agent.get(`${endPoint('createAuthorIfNotExistsFor')}&authorMapper=chris`) await preparedAgent.get(`${endPoint('createAuthorIfNotExistsFor')}?authorMapper=chris`)
.set("Authorization", await generateJWTToken())
.expect(200) .expect(200)
.expect('Content-Type', /json/) .expect('Content-Type', /json/)
.expect((res:any) => { .expect((res:any) => {
@ -240,7 +266,8 @@ describe(__filename, function () {
}); });
it('getAuthorName', async function () { it('getAuthorName', async function () {
await agent.get(`${endPoint('getAuthorName')}&authorID=${authorID}`) await preparedAgent.get(`${endPoint('getAuthorName')}?authorID=${authorID}`)
.set("Authorization", await generateJWTToken())
.expect(200) .expect(200)
.expect('Content-Type', /json/) .expect('Content-Type', /json/)
.expect((res:any) => { .expect((res:any) => {
@ -252,8 +279,9 @@ describe(__filename, function () {
describe('API: Sessions', function () { describe('API: Sessions', function () {
it('createSession', async function () { it('createSession', async function () {
await agent.get(`${endPoint('createSession')}&authorID=${authorID}&groupID=${groupID}` + await preparedAgent.get(`${endPoint('createSession')}?authorID=${authorID}&groupID=${groupID}` +
'&validUntil=999999999999') '&validUntil=999999999999')
.set("Authorization", await generateJWTToken())
.expect(200) .expect(200)
.expect('Content-Type', /json/) .expect('Content-Type', /json/)
.expect((res:any) => { .expect((res:any) => {
@ -264,7 +292,8 @@ describe(__filename, function () {
}); });
it('getSessionInfo', async function () { it('getSessionInfo', async function () {
await agent.get(`${endPoint('getSessionInfo')}&sessionID=${sessionID}`) await preparedAgent.get(`${endPoint('getSessionInfo')}?sessionID=${sessionID}`)
.set("Authorization", await generateJWTToken())
.expect(200) .expect(200)
.expect('Content-Type', /json/) .expect('Content-Type', /json/)
.expect((res:any) => { .expect((res:any) => {
@ -276,7 +305,8 @@ describe(__filename, function () {
}); });
it('listSessionsOfGroup', async function () { it('listSessionsOfGroup', async function () {
await agent.get(`${endPoint('listSessionsOfGroup')}&groupID=${groupID}`) await preparedAgent.get(`${endPoint('listSessionsOfGroup')}?groupID=${groupID}`)
.set("Authorization", await generateJWTToken())
.expect(200) .expect(200)
.expect('Content-Type', /json/) .expect('Content-Type', /json/)
.expect((res:any) => { .expect((res:any) => {
@ -286,7 +316,8 @@ describe(__filename, function () {
}); });
it('deleteSession', async function () { it('deleteSession', async function () {
await agent.get(`${endPoint('deleteSession')}&sessionID=${sessionID}`) await preparedAgent.get(`${endPoint('deleteSession')}?sessionID=${sessionID}`)
.set("Authorization", await generateJWTToken())
.expect(200) .expect(200)
.expect('Content-Type', /json/) .expect('Content-Type', /json/)
.expect((res:any) => { .expect((res:any) => {
@ -295,7 +326,8 @@ describe(__filename, function () {
}); });
it('getSessionInfo of deleted session', async function () { it('getSessionInfo of deleted session', async function () {
await agent.get(`${endPoint('getSessionInfo')}&sessionID=${sessionID}`) await preparedAgent.get(`${endPoint('getSessionInfo')}?sessionID=${sessionID}`)
.set("Authorization", await generateJWTToken())
.expect(200) .expect(200)
.expect('Content-Type', /json/) .expect('Content-Type', /json/)
.expect((res:any) => { .expect((res:any) => {
@ -306,7 +338,8 @@ describe(__filename, function () {
describe('API: Group pad management', function () { describe('API: Group pad management', function () {
it('listPads', async function () { it('listPads', async function () {
await agent.get(`${endPoint('listPads')}&groupID=${groupID}`) await preparedAgent.get(`${endPoint('listPads')}?groupID=${groupID}`)
.set("Authorization", await generateJWTToken())
.expect(200) .expect(200)
.expect('Content-Type', /json/) .expect('Content-Type', /json/)
.expect((res:any) => { .expect((res:any) => {
@ -316,7 +349,8 @@ describe(__filename, function () {
}); });
it('createGroupPad', async function () { it('createGroupPad', async function () {
await agent.get(`${endPoint('createGroupPad')}&groupID=${groupID}&padName=${padID}`) await preparedAgent.get(`${endPoint('createGroupPad')}?groupID=${groupID}&padName=${padID}`)
.set("Authorization", await generateJWTToken())
.expect(200) .expect(200)
.expect('Content-Type', /json/) .expect('Content-Type', /json/)
.expect((res:any) => { .expect((res:any) => {
@ -326,10 +360,11 @@ describe(__filename, function () {
}); });
it('listPads after creating a group pad', async function () { it('listPads after creating a group pad', async function () {
await agent.get(`${endPoint('listPads')}&groupID=${groupID}`) await preparedAgent.get(`${endPoint('listPads')}?groupID=${groupID}`)
.set("Authorization", await generateJWTToken())
.expect(200) .expect(200)
.expect('Content-Type', /json/) .expect('Content-Type', /json/)
.expect((res:any) => { .expect((res) => {
assert.equal(res.body.code, 0); assert.equal(res.body.code, 0);
assert.equal(res.body.data.padIDs.length, 1); assert.equal(res.body.data.padIDs.length, 1);
}); });
@ -338,7 +373,8 @@ describe(__filename, function () {
describe('API: Pad security', function () { describe('API: Pad security', function () {
it('getPublicStatus', async function () { it('getPublicStatus', async function () {
await agent.get(`${endPoint('getPublicStatus')}&padID=${padID}`) await preparedAgent.get(`${endPoint('getPublicStatus')}?padID=${padID}`)
.set("Authorization", await generateJWTToken())
.expect(200) .expect(200)
.expect('Content-Type', /json/) .expect('Content-Type', /json/)
.expect((res:any) => { .expect((res:any) => {
@ -348,7 +384,8 @@ describe(__filename, function () {
}); });
it('setPublicStatus', async function () { it('setPublicStatus', async function () {
await agent.get(`${endPoint('setPublicStatus')}&padID=${padID}&publicStatus=true`) await preparedAgent.get(`${endPoint('setPublicStatus')}?padID=${padID}&publicStatus=true`)
.set("Authorization", await generateJWTToken())
.expect(200) .expect(200)
.expect('Content-Type', /json/) .expect('Content-Type', /json/)
.expect((res:any) => { .expect((res:any) => {
@ -357,7 +394,8 @@ describe(__filename, function () {
}); });
it('getPublicStatus after changing public status', async function () { it('getPublicStatus after changing public status', async function () {
await agent.get(`${endPoint('getPublicStatus')}&padID=${padID}`) await preparedAgent.get(`${endPoint('getPublicStatus')}?padID=${padID}`)
.set("Authorization", await generateJWTToken())
.expect(200) .expect(200)
.expect('Content-Type', /json/) .expect('Content-Type', /json/)
.expect((res:any) => { .expect((res:any) => {
@ -373,7 +411,8 @@ describe(__filename, function () {
describe('API: Misc', function () { describe('API: Misc', function () {
it('listPadsOfAuthor', async function () { it('listPadsOfAuthor', async function () {
await agent.get(`${endPoint('listPadsOfAuthor')}&authorID=${authorID}`) await preparedAgent.get(`${endPoint('listPadsOfAuthor')}?authorID=${authorID}`)
.set("Authorization", await generateJWTToken())
.expect(200) .expect(200)
.expect('Content-Type', /json/) .expect('Content-Type', /json/)
.expect((res:any) => { .expect((res:any) => {

View file

@ -650,5 +650,23 @@
/* /*
* Enable/Disable case-insensitive pad names. * Enable/Disable case-insensitive pad names.
*/ */
"lowerCasePadIds": false "lowerCasePadIds": false,
"sso": {
"clients": [
{
"client_id": "admin_client",
"client_secret": "admin",
"grant_types": ["authorization_code"],
"response_types": ["code"],
"redirect_uris": ["http://localhost:9001/admin/"]
},
{
"client_id": "user_client",
"client_secret": "user",
"grant_types": ["authorization_code"],
"response_types": ["code"],
"redirect_uris": ["http://localhost:9001/"]
}
]
}
} }