master
Sven Slootweg 5 years ago
parent 2aa7be6e9a
commit 82af54b214

@ -0,0 +1,78 @@
module.exports = {
"env": {
"browser": true,
"commonjs": true,
"es6": true,
"node": true
},
"parserOptions": {
"ecmaFeatures": {
"experimentalObjectRestSpread": true,
"jsx": true
}
},
"plugins": [
"react"
],
"rules": {
/* Things that should effectively be syntax errors. */
"indent": [ "error", "tab", {
SwitchCase: 1
}],
"linebreak-style": [ "error", "unix" ],
"semi": [ "error", "always" ],
/* Things that are always mistakes. */
"getter-return": [ "error" ],
"no-compare-neg-zero": [ "error" ],
"no-dupe-args": [ "error" ],
"no-dupe-keys": [ "error" ],
"no-duplicate-case": [ "error" ],
"no-empty": [ "error" ],
"no-empty-character-class": [ "error" ],
"no-ex-assign": [ "error" ],
"no-extra-semi": [ "error" ],
"no-func-assign": [ "error" ],
"no-invalid-regexp": [ "error" ],
"no-irregular-whitespace": [ "error" ],
"no-obj-calls": [ "error" ],
"no-sparse-arrays": [ "error" ],
"no-undef": [ "error" ],
"no-unreachable": [ "error" ],
"no-unsafe-finally": [ "error" ],
"use-isnan": [ "error" ],
"valid-typeof": [ "error" ],
"curly": [ "error" ],
"no-caller": [ "error" ],
"no-fallthrough": [ "error" ],
"no-extra-bind": [ "error" ],
"no-extra-label": [ "error" ],
"array-callback-return": [ "error" ],
"prefer-promise-reject-errors": [ "error" ],
"no-with": [ "error" ],
"no-useless-concat": [ "error" ],
"no-unused-labels": [ "error" ],
"no-unused-expressions": [ "error" ],
"no-unused-vars": [ "error" , { argsIgnorePattern: "^_" } ],
"no-return-assign": [ "error" ],
"no-self-assign": [ "error" ],
"no-new-wrappers": [ "error" ],
"no-redeclare": [ "error" ],
"no-loop-func": [ "error" ],
"no-implicit-globals": [ "error" ],
"strict": [ "error", "global" ],
/* Make JSX not cause 'unused variable' errors. */
"react/jsx-uses-react": ["error"],
"react/jsx-uses-vars": ["error"],
/* Development code that should be removed before deployment. */
"no-console": [ "warn" ],
"no-constant-condition": [ "warn" ],
"no-debugger": [ "warn" ],
"no-alert": [ "warn" ],
"no-warning-comments": ["warn", {
terms: ["fixme"]
}],
/* Common mistakes that can *occasionally* be intentional. */
"no-template-curly-in-string": ["warn"],
"no-unsafe-negation": [ "warn" ],
}
};

3
.gitignore vendored

@ -1 +1,2 @@
node_modules
node_modules
config.json

@ -2,12 +2,60 @@
const express = require("express");
const expressPromiseRouter = require("express-promise-router");
const bodyParser = require("body-parser");
const cors = require("cors");
const url = require("url");
const debugMiddleware = require("./src/debug-middleware");
const accessTokenMiddleware = require("./src/middlewares/access-token");
const clientApiRouter = require("./src/routers/client-api");
const configuration = require("./config.json");
let baseUrl = url.format({
protocol: (configuration.tls) ? "https" : "http",
host: configuration.hostname
});
let state = {
configuration
};
let app = express();
let router = expressPromiseRouter();
router.use(bodyParser.json());
router.use(accessTokenMiddleware);
router.use(debugMiddleware());
router.options("*", cors({
methods: ["GET", "POST", "PUT", "DELETE", "OPTIONS"],
allowedHeaders: ["Origin", "X-Requested-With", "Content-Type", "Accept", "Authorization"],
optionsSuccessStatus: 200
}));
router.use("/_matrix/client", clientApiRouter(state));
router.get("/", (req, res) => {
res.send("Hello world")
res.send("Hello world!");
});
router.get("/.well-known/matrix/client", (req, res) => {
let response = {
"m.homeserver": {
base_url: baseUrl
}
};
if (configuration.identity_server != null) {
response["m.identity_server"] = {
base_url: configuration.identity_server
};
}
res.json(response);
});
app.use(router);

@ -0,0 +1,19 @@
"use strict";
const url = require("url");
const config = require("./config.json");
module.exports = {
client: "pg",
connection: {
connectionString: url.format({
protocol: "socket",
slashes: false,
pathname: config.database.socket,
query: {
db: config.database.database
}
})
}
};

@ -6,7 +6,18 @@
"author": "Sven Slootweg <admin@cryto.net>",
"license": "WTFPL OR CC0-1.0",
"dependencies": {
"bluebird": "^3.5.4",
"body-parser": "^1.19.0",
"chalk": "^2.4.2",
"cors": "^2.8.5",
"default-value": "^1.0.0",
"express": "^4.16.4",
"express-promise-router": "^3.0.3"
"express-promise-router": "^3.0.3",
"knex": "^0.16.5",
"pg": "^7.10.0"
},
"devDependencies": {
"eslint": "^5.16.0",
"eslint-plugin-react": "^7.12.4"
}
}

@ -0,0 +1,7 @@
"use strict";
module.exports = function ({db}) {
return {
};
};

@ -0,0 +1,21 @@
"use strict";
const util = require("util");
const chalk = require("chalk");
module.exports = function createDebugMiddleware() {
return function (req, res, next) {
console.log(`## ${chalk.cyan(req.method)} ${chalk.bold.yellow(req.url)}`);
console.log(util.inspect({
query: req.query,
params: req.params,
host: req.hostname,
headers: req.headers,
cookies: req.cookies,
body: req.body
}, {colors: true, depth: null}));
next();
}
};

@ -0,0 +1,71 @@
"use strict";
const errorChain = require("error-chain");
let HttpError = errorChain("HttpError", { isHttpError: true });
/*** HTTP 400: Bad Request ***/
let BadRequest = HttpError.extend("BadRequest", { statusCode: 400, errorCode: "M_UNRECOGNIZED" });
let NotJson = BadRequest.extend("NotJson", { errorCode: "M_NOT_JSON" });
let BadJson = BadRequest.extend("BadJson", { errorCode: "M_BAD_JSON" });
/*** HTTP 401: Unauthorized ***/
let Unauthorized = HttpError.extend("Unauthorized", { statusCode: 401, errorCode: "M_UNAUTHORIZED" });
let MissingAccessToken = Unauthorized.extend("MissingAccessToken", { errorCode: "M_MISSING_TOKEN" });
let MissingCaptcha = Unauthorized.extend("MissingCaptcha", { errorCode: "M_CAPTCHA_NEEDED" });
/*** HTTP 403: Forbidden ***/
let Forbidden = HttpError.extend("Forbidden", { statusCode: 403, errorCode: "M_FORBIDDEN" });
let InvalidAccessToken = Forbidden.extend("InvalidAccessToken", { errorCode: "M_UNKNOWN_TOKEN" });
let InvalidCaptcha = Forbidden.extend("InvalidCaptcha", { errorCode: "M_CAPTCHA_INVALID" });
let ServerNotTrusted = Forbidden.extend("ServerNotTrusted", { errorCode: "M_SERVER_NOT_TRUSTED" });
let NoGuestAccess = Forbidden.extend("NoGuestAccess", { errorCode: "M_GUEST_ACCESS_FORBIDDEN" });
let ExternalIdentifierAuthenticationFailed = Forbidden.extend("ExternalIdentifierAuthenticationFailed", { errorCode: "M_THREEPID_AUTH_FAILED" });
/*** HTTP 404: Not Found ***/
let NotFound = HttpError.extend("NotFound", { statusCode: 404, errorCode: "M_NOT_FOUND" });
let ExternalIdentifierNotFound = NotFound.extend("ExternalIdentifierNotFound", { errorCode: "M_THREEPID_NOT_FOUND" });
/*** HTTP 409: Conflict ***/
let ResourceExists = HttpError.extend("ResourceExists", { statusCode: 409 });
let UserExists = ResourceExists.extend("UserExists", { errorCode: "M_USER_IN_USE" });
let RoomExists = ResourceExists.extend("RoomExists", { errorCode: "M_ROOM_IN_USE" });
let ExternalIdentifierExists = ResourceExists.extend("ExternalIdentifierExists", { errorCode: "M_THREEPID_IN_USE" });
/*** HTTP 413: Payload Too Large ***/
let RequestTooLarge = HttpError.extend("RequestTooLarge", { statusCode: 413, errorCode: "M_TOO_LARGE" });
/*** HTTP 422: Unprocessable Entity (Invalid Payload) ***/
let InvalidData = HttpError.extend("InvalidData", { statusCode: 422 });
let InvalidUsername = InvalidData.extend("InvalidUsername", { errorCode: "M_INVALID_USERNAME" });
let InvalidRoomVersion = InvalidData.extend("InvalidRoomVersion", { errorCode: "M_UNSUPPORTED_ROOM_VERSION" });
let InvalidRoomState = InvalidData.extend("InvalidRoomState", { errorCode: "M_INVALID_ROOM_STATE" });
let InvalidStateChange = InvalidData.extend("InvalidStateChange", { errorCode: "M_BAD_STATE" });
let InvalidExternalIdentifier = InvalidData.extend("InvalidExternalIdentifier", { errorCode: "M_THREEPID_DENIED" });
let InvalidParameter = InvalidData.extend("InvalidParameter", { errorCode: "M_INVALID_PARAM" });
let MissingParameter = InvalidData.extend("MissingParameter", { errorCode: "M_MISSING_PARAM" });
let IncompatibleRoomVersion = InvalidData.extend("IncompatibleRoomVersion", { errorCode: "M_INCOMPATIBLE_ROOM_VERSION" });
/*** HTTP 429: Too Many Requests ***/
let TooManyRequests = HttpError.extend("TooManyRequests", { statusCode: 429, errorCode: "M_LIMIT_EXCEEDED" });
/*** HTTP 500: Internal Server Error ***/
let InternalServerError = HttpError.extend("InternalServerError", { statusCode: 500 });
let UnknownError = InternalServerError.extend("UnknownError", { errorCode: "M_UNKNOWN" });
/*** HTTP 503: Service Unavailable ***/
let ExclusiveResource = HttpError.extend("ExclusiveResource", { statusCode: 503, errorCode: "M_EXCLUSIVE" });
module.exports = {
HttpError, Unauthorized, MissingAccessToken, InvalidAccessToken, NotJson, BadJson, NotFound, TooManyRequests, MissingCaptcha, InvalidCaptcha, ServerNotTrusted, NoGuestAccess, UserExists, RoomExists, RequestTooLarge, InvalidUsername, InvalidRoomVersion, InvalidRoomState, InvalidStateChange, InvalidParameter, MissingParameter, IncompatibleRoomVersion, InternalServerError, UnknownError, ExclusiveResource, ResourceExists, Forbidden, BadRequest, ExternalIdentifierNotFound, ExternalIdentifierExists, ExternalIdentifierAuthenticationFailed, InvalidExternalIdentifier
};

@ -0,0 +1,8 @@
"use strict";
const defaultValue = require("default-value");
module.exports = function (req, _res, next) {
req.matrixAccessToken = defaultValue(req.query.access_token, req.headers.Authorization);
next();
};

@ -0,0 +1,28 @@
"use strict";
const defaultValue = require("default-value");
const http = require("http");
module.exports = function errorHandler(error, _req, res, _next) {
let statusCode = (error.isHttpError && error.statusCode != null)
? error.statusCode
: 500;
let errorCode = (error.isHttpError && error.errorCode != null)
? error.errorCode
: "M_UNKNOWN";
let errorMessage = (error.errorCode !== 500)
? defaultValue(error.message, http.STATUS_CODES[statusCode])
: "An internal server error occurred. Please contact the server administrator for more information."
/* TODO: Add contact details? */
let errorMeta = (error.errorMeta != null)
? error.errorMeta
: {};
res.json(Object.assign({}, errorMeta, {
errcode: errorCode,
error: errorMessage
}));
};

@ -0,0 +1,11 @@
"use strict";
const errors = require("../errors");
module.exports = function requireAccessToken(req, res, next) {
if (req.matrixAccessToken == null) {
throw new errors.UnauthorizedError("An access token is required, but none was provided", {
errorCode: "M_MISSING_TOKEN"
});
}
};

@ -0,0 +1,16 @@
"use strict";
module.exports = function(state) {
let router = require("express-promise-router")();
router.get("/versions", (req, res) => {
/* TODO: Support more specification versions? */
res.json({
versions: [
"r0.4.0"
]
});
});
return router;
}

File diff suppressed because it is too large Load Diff
Loading…
Cancel
Save