From c5b803343e58a1a9236e4463bc54c1b30f17b8f1 Mon Sep 17 00:00:00 2001 From: Travis Ralston Date: Sun, 24 Dec 2017 02:28:48 -0700 Subject: [PATCH] Move app from src-ts to src --- .gitignore | 4 +- src/Dimension.js | 67 ---- src/DimensionApi.js | 307 ------------------ {src-ts => src}/MemoryCache.ts | 0 src/OpenID.js | 11 - src/ScalarApi.js | 115 ------- src/UpstreamConfiguration.js | 50 --- {src-ts => src}/api/ApiError.ts | 0 {src-ts => src}/api/Webserver.ts | 0 .../api/dimension/DimensionAdminService.ts | 0 .../DimensionAppserviceAdminService.ts | 0 .../DimensionIntegrationsAdminService.ts | 0 .../dimension/DimensionIntegrationsService.ts | 0 .../api/matrix/MatrixAppServiceApiService.ts | 0 {src-ts => src}/api/scalar/ScalarService.ts | 0 .../api/scalar/ScalarWidgetService.ts | 0 {src-ts => src}/config.ts | 0 {src-ts => src}/db/AppserviceStore.ts | 0 {src-ts => src}/db/DimensionStore.ts | 0 {src-ts => src}/db/ScalarStore.ts | 0 {src-ts => src}/db/WidgetStore.ts | 0 .../db/migrations/20171218203245-AddTables.ts | 0 .../migrations/20171218203245-AddWidgets.ts | 0 .../20171224122045-AddAppservices.ts | 0 .../20171224124645-AddAppserviceUsers.ts | 0 {src-ts => src}/db/models/AppService.ts | 0 {src-ts => src}/db/models/AppServiceUser.ts | 0 .../db/models/IntegrationRecord.ts | 0 {src-ts => src}/db/models/Upstream.ts | 0 {src-ts => src}/db/models/User.ts | 0 {src-ts => src}/db/models/UserScalarToken.ts | 0 {src-ts => src}/db/models/WidgetRecord.ts | 0 {src-ts => src}/index.ts | 0 src/integration/generic_types/Bridge.js | 22 -- src/integration/generic_types/ComplexBot.js | 18 - .../generic_types/IntegrationStub.js | 44 --- src/integration/generic_types/Widget.js | 22 -- src/integration/impl/StubbedFactory.js | 20 -- src/integration/impl/circleci/CircleCiBot.js | 53 --- .../impl/circleci/CircleCiFactory.js | 20 -- .../impl/circleci/StubbedCircleCiBackbone.js | 63 ---- .../impl/circleci/VectorCircleCiBackbone.js | 108 ------ src/integration/impl/index.js | 46 --- src/integration/impl/irc/IRCApi.js | 114 ------- src/integration/impl/irc/IRCBridge.js | 75 ----- src/integration/impl/irc/IRCFactory.js | 20 -- .../impl/irc/StubbedIrcBackbone.js | 60 ---- src/integration/impl/irc/VectorIrcBackbone.js | 120 ------- src/integration/impl/rss/RSSBot.js | 49 --- src/integration/impl/rss/RSSFactory.js | 20 -- .../impl/rss/StubbedRssBackbone.js | 55 ---- src/integration/impl/rss/VectorRssBackbone.js | 82 ----- .../impl/simple_bot/HostedSimpleBackbone.js | 31 -- src/integration/impl/simple_bot/SimpleBot.js | 24 -- .../impl/simple_bot/SimpleBotFactory.js | 27 -- .../impl/simple_bot/StubbedSimpleBackbone.js | 24 -- .../impl/simple_bot/VectorSimpleBackbone.js | 28 -- .../impl/simple_widget/SimpleWidget.js | 17 - .../impl/simple_widget/SimpleWidgetFactory.js | 13 - .../impl/travisci/StubbedTravisCiBackbone.js | 63 ---- src/integration/impl/travisci/TravisCiBot.js | 53 --- .../impl/travisci/TravisCiFactory.js | 20 -- .../impl/travisci/VectorTravisCiBackbone.js | 108 ------ src/integration/index.js | 78 ----- {src-ts => src}/integrations/Integration.ts | 0 {src-ts => src}/integrations/Widget.ts | 0 src/matrix/DemoBot.js | 66 ---- .../matrix/MatrixAppserviceClient.ts | 0 src/matrix/MatrixLiteClient.js | 96 +----- {src-ts => src}/matrix/MatrixLiteClient.ts | 0 {src-ts => src}/matrix/MatrixOpenIdClient.ts | 0 {src-ts => src}/matrix/helpers.ts | 0 {src-ts => src}/models/MatrixEvent.ts | 0 {src-ts => src}/models/OpenId.ts | 0 {src-ts => src}/models/ScalarResponses.ts | 0 src/scalar/ScalarClient.js | 84 ++--- {src-ts => src}/scalar/ScalarClient.ts | 0 src/scalar/VectorScalarClient.js | 260 --------------- src/storage/DimensionStore.js | 120 ------- src/storage/models/tokens.js | 45 --- {src-ts => src}/temp_todo.txt | 0 src/util/LogService.js | 100 ------ {src-ts => src}/version.ts | 0 tsconfig-app.json | 2 +- 84 files changed, 49 insertions(+), 2775 deletions(-) delete mode 100644 src/Dimension.js delete mode 100644 src/DimensionApi.js rename {src-ts => src}/MemoryCache.ts (100%) delete mode 100644 src/OpenID.js delete mode 100644 src/ScalarApi.js delete mode 100644 src/UpstreamConfiguration.js rename {src-ts => src}/api/ApiError.ts (100%) rename {src-ts => src}/api/Webserver.ts (100%) rename {src-ts => src}/api/dimension/DimensionAdminService.ts (100%) rename {src-ts => src}/api/dimension/DimensionAppserviceAdminService.ts (100%) rename {src-ts => src}/api/dimension/DimensionIntegrationsAdminService.ts (100%) rename {src-ts => src}/api/dimension/DimensionIntegrationsService.ts (100%) rename {src-ts => src}/api/matrix/MatrixAppServiceApiService.ts (100%) rename {src-ts => src}/api/scalar/ScalarService.ts (100%) rename {src-ts => src}/api/scalar/ScalarWidgetService.ts (100%) rename {src-ts => src}/config.ts (100%) rename {src-ts => src}/db/AppserviceStore.ts (100%) rename {src-ts => src}/db/DimensionStore.ts (100%) rename {src-ts => src}/db/ScalarStore.ts (100%) rename {src-ts => src}/db/WidgetStore.ts (100%) rename {src-ts => src}/db/migrations/20171218203245-AddTables.ts (100%) rename {src-ts => src}/db/migrations/20171218203245-AddWidgets.ts (100%) rename {src-ts => src}/db/migrations/20171224122045-AddAppservices.ts (100%) rename {src-ts => src}/db/migrations/20171224124645-AddAppserviceUsers.ts (100%) rename {src-ts => src}/db/models/AppService.ts (100%) rename {src-ts => src}/db/models/AppServiceUser.ts (100%) rename {src-ts => src}/db/models/IntegrationRecord.ts (100%) rename {src-ts => src}/db/models/Upstream.ts (100%) rename {src-ts => src}/db/models/User.ts (100%) rename {src-ts => src}/db/models/UserScalarToken.ts (100%) rename {src-ts => src}/db/models/WidgetRecord.ts (100%) rename {src-ts => src}/index.ts (100%) delete mode 100644 src/integration/generic_types/Bridge.js delete mode 100644 src/integration/generic_types/ComplexBot.js delete mode 100644 src/integration/generic_types/IntegrationStub.js delete mode 100644 src/integration/generic_types/Widget.js delete mode 100644 src/integration/impl/StubbedFactory.js delete mode 100644 src/integration/impl/circleci/CircleCiBot.js delete mode 100644 src/integration/impl/circleci/CircleCiFactory.js delete mode 100644 src/integration/impl/circleci/StubbedCircleCiBackbone.js delete mode 100644 src/integration/impl/circleci/VectorCircleCiBackbone.js delete mode 100644 src/integration/impl/index.js delete mode 100644 src/integration/impl/irc/IRCApi.js delete mode 100644 src/integration/impl/irc/IRCBridge.js delete mode 100644 src/integration/impl/irc/IRCFactory.js delete mode 100644 src/integration/impl/irc/StubbedIrcBackbone.js delete mode 100644 src/integration/impl/irc/VectorIrcBackbone.js delete mode 100644 src/integration/impl/rss/RSSBot.js delete mode 100644 src/integration/impl/rss/RSSFactory.js delete mode 100644 src/integration/impl/rss/StubbedRssBackbone.js delete mode 100644 src/integration/impl/rss/VectorRssBackbone.js delete mode 100644 src/integration/impl/simple_bot/HostedSimpleBackbone.js delete mode 100644 src/integration/impl/simple_bot/SimpleBot.js delete mode 100644 src/integration/impl/simple_bot/SimpleBotFactory.js delete mode 100644 src/integration/impl/simple_bot/StubbedSimpleBackbone.js delete mode 100644 src/integration/impl/simple_bot/VectorSimpleBackbone.js delete mode 100644 src/integration/impl/simple_widget/SimpleWidget.js delete mode 100644 src/integration/impl/simple_widget/SimpleWidgetFactory.js delete mode 100644 src/integration/impl/travisci/StubbedTravisCiBackbone.js delete mode 100644 src/integration/impl/travisci/TravisCiBot.js delete mode 100644 src/integration/impl/travisci/TravisCiFactory.js delete mode 100644 src/integration/impl/travisci/VectorTravisCiBackbone.js delete mode 100644 src/integration/index.js rename {src-ts => src}/integrations/Integration.ts (100%) rename {src-ts => src}/integrations/Widget.ts (100%) delete mode 100644 src/matrix/DemoBot.js rename {src-ts => src}/matrix/MatrixAppserviceClient.ts (100%) rename {src-ts => src}/matrix/MatrixLiteClient.ts (100%) rename {src-ts => src}/matrix/MatrixOpenIdClient.ts (100%) rename {src-ts => src}/matrix/helpers.ts (100%) rename {src-ts => src}/models/MatrixEvent.ts (100%) rename {src-ts => src}/models/OpenId.ts (100%) rename {src-ts => src}/models/ScalarResponses.ts (100%) rename {src-ts => src}/scalar/ScalarClient.ts (100%) delete mode 100644 src/scalar/VectorScalarClient.js delete mode 100644 src/storage/DimensionStore.js delete mode 100644 src/storage/models/tokens.js rename {src-ts => src}/temp_todo.txt (100%) delete mode 100644 src/util/LogService.js rename {src-ts => src}/version.ts (100%) diff --git a/.gitignore b/.gitignore index 1de6ce0..3d0f9d9 100644 --- a/.gitignore +++ b/.gitignore @@ -10,8 +10,8 @@ config/integrations/*_development.yaml config/integrations/*_production.yaml build/ dimension.db -src-ts/**/*.js -src-ts/**/*.js.map +src/**/*.js +src/**/*.js.map web/**/*.js web/**/*.js.map diff --git a/src/Dimension.js b/src/Dimension.js deleted file mode 100644 index 3914722..0000000 --- a/src/Dimension.js +++ /dev/null @@ -1,67 +0,0 @@ -var express = require("express"); -var config = require("config"); -var log = require("./util/LogService"); -var DimensionStore = require("./storage/DimensionStore"); -var bodyParser = require('body-parser'); -var path = require("path"); -var DimensionApi = require("./DimensionApi"); -var ScalarApi = require("./ScalarApi"); -var IRCApi = require("./integration/impl/irc/IRCApi"); -var URL = require("url"); - -// TODO: Convert backend to typescript? Would avoid stubbing classes all over the place - -/** - * Primary entry point for Dimension - */ -class Dimension { - - /** - * Creates a new Dimension - */ - constructor() { - } - - /** - * Starts the Dimension service - * @param {DimensionStore} db the store to use - */ - start(db) { - this._db = db; - this._app = express(); - this._app.use(express.static('web-dist')); - this._app.use(bodyParser.json()); - - // Register routes for angular app - this._app.get(['/riot', '/riot/*', '/widgets', '/widgets/*'], (req, res) => { - res.sendFile(path.join(__dirname, "..", "web-dist", "index.html")); - }); - - // Allow CORS - this._app.use((req, res, next) => { - res.setHeader("Access-Control-Allow-Origin", "*"); - res.setHeader("Access-Control-Allow-Headers", "Origin, X-Requested-With, Content-Type, Accept"); - next(); - }); - - // Logging incoming requests - this._app.use((req, res, next) => { - var parsedUrl = URL.parse(req.url, true); - if (parsedUrl.query && parsedUrl.query["scalar_token"]) { - parsedUrl.query["scalar_token"] = "redacted"; - parsedUrl.search = undefined; // to trigger the URL.format to use `query` - } - log.verbose("Dimension", "Incoming: " + req.method + " " + URL.format(parsedUrl)); - next(); - }); - - DimensionApi.bootstrap(this._app, this._db); - ScalarApi.bootstrap(this._app, this._db); - IRCApi.bootstrap(this._app, this._db); - - this._app.listen(config.get('web.port'), config.get('web.address')); - log.info("Dimension", "API and UI listening on " + config.get("web.address") + ":" + config.get("web.port")); - } -} - -module.exports = new Dimension(); \ No newline at end of file diff --git a/src/DimensionApi.js b/src/DimensionApi.js deleted file mode 100644 index 28f3061..0000000 --- a/src/DimensionApi.js +++ /dev/null @@ -1,307 +0,0 @@ -const IntegrationImpl = require("./integration/impl/index"); -const Integrations = require("./integration/index"); -const _ = require("lodash"); -const log = require("./util/LogService"); -const request = require("request"); -const dns = require("dns-then"); -const urlParse = require("url"); -const Netmask = require("netmask").Netmask; -const config = require("config"); - -/** - * API handler for the Dimension API - */ -class DimensionApi { - - /** - * Creates a new Dimension API - */ - constructor() { - } - - /** - * Bootstraps the Dimension API - * @param {*} app the Express application - * @param {DimensionStore} db the store to use - */ - bootstrap(app, db) { - this._db = db; - - app.get("/api/v1/dimension/integrations/:roomId", this._getIntegrations.bind(this)); - app.delete("/api/v1/dimension/integrations/:roomId/:type/:integrationType", this._removeIntegration.bind(this)); - app.put("/api/v1/dimension/integrations/:roomId/:type/:integrationType/state", this._updateIntegrationState.bind(this)); - app.get("/api/v1/dimension/integrations/:roomId/:type/:integrationType/state", this._getIntegrationState.bind(this)); - app.get("/api/v1/dimension/widgets/embeddable", this._checkEmbeddable.bind(this)); - app.get("/api/v1/dimension/integration/:type/:integrationType", this._getIntegration.bind(this)); - app.get("/api/v1/dimension/whoami", this._getTokenOwner.bind(this)); - } - - _getTokenOwner(req, res) { - res.setHeader("Content-Type", "application/json"); - - var scalarToken = req.query.scalar_token; - if (!scalarToken) { - res.status(400).send({error: 'Missing scalar token'}); - return; - } - - this._db.getTokenOwner(scalarToken).then(userId => { - res.status(200).send({userId: userId}); - }).catch(err => { - log.error("DimensionApi", err); - console.error(err); - res.status(401).send({error: 'Invalid token or other error'}); - }); - } - - _checkEmbeddable(req, res) { - // Unauthed endpoint. - - var url = req.query.url; - var parts = urlParse.parse(url); - var processed = false; - - // Only allow http and https - if (parts.protocol !== "http:" && parts.protocol !== "https:") { - res.status(400).send({error: "Invalid request scheme " + parts.protocol, canEmbed: false}); - processed = true; - return; - } - - // Verify the address is permitted for widgets - var hostname = parts.hostname.split(":")[0]; - dns.resolve4(hostname).then(addresses => { - log.verbose("DimensionApi", "Hostname " + hostname + " resolves to " + addresses); - if (addresses.length == 0) { - res.status(400).send({error: "Unrecongized address", canEmbed: false}); - processed = true; - return; - } - for (var ipOrCidr of config.get("widgetBlacklist")) { - var block = new Netmask(ipOrCidr); - for (var address of addresses) { - if (block.contains(address)) { - res.status(400).send({error: "Address not allowed", canEmbed: false}); - processed = true; - return; - } - } - } - }, err => { - log.verbose("DimensionApi", "Error resolving host " + hostname); - log.verbose("DimensionApi", err); - - res.status(400).send({error: "DNS error", canEmbed: false}); - processed = true; - }).then(() => { - if (processed) return; - - // Verify that the content can actually be embedded (CORS) - request(url, (err, response) => { - if (err) { - log.verbose("DimensionApi", "Error contacting host " + hostname); - log.verbose("DimensionApi", err); - - res.status(400).send({error: "Host error", canEmbed: false}); - return; - } - - if (response.statusCode >= 200 && response.statusCode < 300) { - // 200 OK - var headers = response.headers; - var xFrameOptions = (headers['x-frame-options'] || '').toLowerCase(); - - if (xFrameOptions === 'sameorigin' || xFrameOptions === 'deny') { - res.status(400).send({error: "X-Frame-Options forbids embedding", canEmbed: false}); - } else res.status(200).send({canEmbed: true}); - } else { - res.status(400).send({error: "Unsuccessful status code: " + response.statusCode, canEmbed: false}); - } - }); - }); - } - - _findIntegration(integrationConfig, roomId, scalarToken) { - var factory = IntegrationImpl.getFactory(integrationConfig); - if (!factory) throw new Error("Missing config factory for " + integrationConfig.name); - - try { - return factory(this._db, integrationConfig, roomId, scalarToken); - } catch (err) { - throw new Error("Error using factory for " + integrationConfig.name + ". Please either fix the integration settings or disable the integration.", err); - } - } - - _getIntegration(req, res) { - res.setHeader("Content-Type", "application/json"); - // Unauthed endpoint. - - var type = req.params.type; - var integrationType = req.params.integrationType; - - if (!type || !integrationType) { - res.status(400).send({error: "Missing integration type or type"}); - return; - } - - var byIntegrationType = Integrations.byType[type]; - if (!byIntegrationType || !byIntegrationType[integrationType]) { - res.status(400).send({error: "Unknown integration"}); - return; - } - var integrationConfig = byIntegrationType[integrationType]; - - res.status(200).send(integrationConfig); - } - - _getIntegrations(req, res) { - res.setHeader("Content-Type", "application/json"); - - var roomId = req.params.roomId; - if (!roomId) { - res.status(400).send({error: 'Missing room ID'}); - return; - } - - var scalarToken = req.query.scalar_token; - this._db.checkToken(scalarToken).then(() => { - var integrations = _.map(Integrations.all, i => JSON.parse(JSON.stringify(i))); // clone - - var promises = []; - var remove = []; - _.forEach(integrations, integration => { - try { - promises.push(this._findIntegration(integration, roomId, scalarToken).then(builtIntegration => { - return builtIntegration.getState().then(state => { - var keys = _.keys(state); - for (var key of keys) { - integration[key] = state[key]; - } - - return builtIntegration.getUserId(); - }).then(userId => { - integration.userId = userId; - }); - })); - } catch (err) { - remove.push(integration); - log.error("DimensionApi", err); - } - }); - - for (var toRemove of remove) { - var idx = integrations.indexOf(toRemove); - if (idx === -1) continue; - log.warn("DimensionApi", "Disabling integration " + toRemove.name + " due to an error encountered in setup"); - integrations.splice(idx, 1); - } - - Promise.all(promises).then(() => res.send(_.map(integrations, integration => { - // Remove sensitive material - integration.upstream = undefined; - integration.hosted = undefined; - return integration; - }))); - }).catch(err => { - log.error("DimensionApi", err); - console.error(err); - res.status(500).send({error: err}); - }); - } - - _removeIntegration(req, res) { - var roomId = req.params.roomId; - var scalarToken = req.query.scalar_token; - var type = req.params.type; - var integrationType = req.params.integrationType; - - if (!roomId || !scalarToken || !type || !integrationType) { - res.status(400).send({error: "Missing room, integration type, type, or token"}); - return; - } - - var integrationConfig = Integrations.byType[type][integrationType]; - if (!integrationConfig) { - res.status(400).send({error: "Unknown integration"}); - return; - } - - log.info("DimensionApi", "Remove requested for " + type + " (" + integrationType + ") in room " + roomId); - - this._db.checkToken(scalarToken).then(() => { - return this._findIntegration(integrationConfig, roomId, scalarToken); - }).then(integration => integration.removeFromRoom(roomId)).then(() => { - res.status(200).send({success: true}); - }).catch(err => { - log.error("DimensionApi", err); - console.error(err); - res.status(500).send({error: err.message}); - }); - } - - _updateIntegrationState(req, res) { - var roomId = req.params.roomId; - var scalarToken = req.body.scalar_token; - var type = req.params.type; - var integrationType = req.params.integrationType; - - if (!roomId || !scalarToken || !type || !integrationType) { - res.status(400).send({error: "Missing room, integration type, type, or token"}); - return; - } - - var integrationConfig = Integrations.byType[type][integrationType]; - if (!integrationConfig) { - res.status(400).send({error: "Unknown integration"}); - return; - } - - log.info("DimensionApi", "Update state requested for " + type + " (" + integrationType + ") in room " + roomId); - - this._db.checkToken(scalarToken).then(() => { - return this._findIntegration(integrationConfig, roomId, scalarToken); - }).then(integration => { - return integration.updateState(req.body.state); - }).then(newState => { - res.status(200).send(newState); - }).catch(err => { - log.error("DimensionApi", err); - console.error(err); - res.status(500).send({error: err.message}); - }); - } - - _getIntegrationState(req, res) { - var roomId = req.params.roomId; - var scalarToken = req.query.scalar_token; - var type = req.params.type; - var integrationType = req.params.integrationType; - - if (!roomId || !scalarToken || !type || !integrationType) { - res.status(400).send({error: "Missing room, integration type, type, or token"}); - return; - } - - var integrationConfig = Integrations.byType[type][integrationType]; - if (!integrationConfig) { - res.status(400).send({error: "Unknown integration"}); - return; - } - - log.info("DimensionApi", "State requested for " + type + " (" + integrationType + ") in room " + roomId); - - this._db.checkToken(scalarToken).then(() => { - return this._findIntegration(integrationConfig, roomId, scalarToken); - }).then(integration => { - return integration.getState(); - }).then(state => { - res.status(200).send(state); - }).catch(err => { - log.error("DimensionApi", err); - console.error(err); - res.status(500).send({error: err.message}); - }); - } -} - -module.exports = new DimensionApi(); diff --git a/src-ts/MemoryCache.ts b/src/MemoryCache.ts similarity index 100% rename from src-ts/MemoryCache.ts rename to src/MemoryCache.ts diff --git a/src/OpenID.js b/src/OpenID.js deleted file mode 100644 index 75e9d12..0000000 --- a/src/OpenID.js +++ /dev/null @@ -1,11 +0,0 @@ -/** - * Serves the purpose of being a documentation endpoint - */ -class OpenID { - access_token = ""; - token_type = ""; - matrix_server_name = ""; - expires_in = 0; -} - -module.exports = OpenID; \ No newline at end of file diff --git a/src/ScalarApi.js b/src/ScalarApi.js deleted file mode 100644 index 528bca1..0000000 --- a/src/ScalarApi.js +++ /dev/null @@ -1,115 +0,0 @@ -var MatrixLiteClient = require("./matrix/MatrixLiteClient"); -var randomString = require("random-string"); -var ScalarClient = require("./scalar/ScalarClient.js"); -var _ = require("lodash"); -var log = require("./util/LogService"); -var Promise = require("bluebird"); -var UpstreamConfiguration = require("./UpstreamConfiguration"); - -/** - * API handler for the Scalar API, as required by Riot - */ -class ScalarApi { - - /** - * Creates a new Scalar API - */ - constructor() { - } - - /** - * Bootstraps the Scalar API - * @param {*} app the Express application - * @param {DimensionStore} db the store to use - */ - bootstrap(app, db) { - this._db = db; - - app.post("/api/v1/scalar/register", this._scalarRegister.bind(this)); - app.get("/api/v1/scalar/checkToken", this._checkScalarToken.bind(this)); - app.get("/api/v1/scalar/widgets/title_lookup", this._getWidgetTitle.bind(this)); - } - - _getWidgetTitle(req, res) { - res.setHeader("Content-Type", "application/json"); - - var token = req.query.scalar_token; - var url = req.query.curl; - - if (!token || !url) { - res.status(400).send({error: "Missing token or curl"}); - return; - } - - this._db.checkToken(token).then(() => { - MatrixLiteClient.getUrlPreview(url).then(preview => { - if (!preview["og:title"]) { - res.status(404).send({error:{message:"Could not locate a title for the URL"}}); - return; - } - - // We need to convert the preview response to what Scalar expects - res.status(200).send({ - cached_response: false, - page_title_cache_item: { - expires: null, // unused - cached_response_err: null, // unused - cached_title: preview["og:title"], - } - }); - }).catch(err => { - res.status(500).send({error: {message: "Failed to get preview"}}); - log.error("ScalarApi", "Failed to get URL preview"); - log.error("ScalarApi", err); - }); - }).catch(err => { - res.status(401).send({error: {message: "Failed to authenticate token"}}); - log.warn("ScalarApi", "Failed to authenticate token"); - log.warn("ScalarApi", err); - }); - } - - _checkScalarToken(req, res) { - var token = req.query.scalar_token; - if (!token) res.sendStatus(400); - else this._db.checkToken(token).then(() => { - res.sendStatus(200); - }).catch(e => { - res.sendStatus(401); - log.warn("ScalarApi", "Failed to authenticate token"); - log.verbose("ScalarApi", e); - }); - } - - _scalarRegister(req, res) { - res.setHeader("Content-Type", "application/json"); - - var tokenInfo = req.body; - if (!tokenInfo || !tokenInfo['access_token'] || !tokenInfo['token_type'] || !tokenInfo['matrix_server_name'] || !tokenInfo['expires_in']) { - res.status(400).send({error: 'Missing OpenID'}); - return; - } - - var client = new MatrixLiteClient(tokenInfo); - var scalarToken = randomString({length: 25}); - var userId; - client.getSelfMxid().then(mxid => { - userId = mxid; - if (!mxid) throw new Error("Token does not resolve to a matrix user"); - - // TODO: Make this part more generic for other upstreams (#22) - if (!UpstreamConfiguration.hasUpstream("vector")) return Promise.resolve(null); - return ScalarClient.register(tokenInfo); - }).then(upstreamToken => { - return this._db.createToken(userId, tokenInfo, scalarToken, upstreamToken); - }).then(() => { - res.setHeader("Content-Type", "application/json"); - res.send({scalar_token: scalarToken}); - }).catch(err => { - log.error("ScalarApi", err); - res.status(500).send({error: err.message}); - }); - } -} - -module.exports = new ScalarApi(); \ No newline at end of file diff --git a/src/UpstreamConfiguration.js b/src/UpstreamConfiguration.js deleted file mode 100644 index de22466..0000000 --- a/src/UpstreamConfiguration.js +++ /dev/null @@ -1,50 +0,0 @@ -var LogService = require("./util/LogService"); -var _ = require("lodash"); -var config = require("config"); - -/** - * Handles all upstream configuration information, such as URLs, tokens, and whether or not they are enabled. - */ -class UpstreamConfiguration { - /** - * Creates a new upstream configuration handler - */ - constructor() { - this._upstreams = {}; - this._loadUpstreams(); - } - - _loadUpstreams() { - for (var upstream of config.upstreams) { - var upstreamConfig = upstream; - - if (this._upstreams[upstream.name]) { - LogService.warn("UpstreamConfiguration", "Duplicate upstream " + upstream.name +" - skipping"); - continue; - } - - this._upstreams[upstream.name] = upstreamConfig; - LogService.info("UpstreamConfiguration", "Loaded upstream '" + upstream.name + "' as: " + JSON.stringify(upstreamConfig)); - } - } - - /** - * Checks if a particular upstream exists - * @param {string} name the name of the upstream - * @returns {boolean} true if it is enabled and exists - */ - hasUpstream(name) { - return !!this._upstreams[name]; - } - - /** - * Gets an upstream's configuration - * @param {string} name the upstream name - * @returns {{url:string}} the upstream configuration - */ - getUpstream(name) { - return _.clone(this._upstreams[name]); - } -} - -module.exports = new UpstreamConfiguration(); \ No newline at end of file diff --git a/src-ts/api/ApiError.ts b/src/api/ApiError.ts similarity index 100% rename from src-ts/api/ApiError.ts rename to src/api/ApiError.ts diff --git a/src-ts/api/Webserver.ts b/src/api/Webserver.ts similarity index 100% rename from src-ts/api/Webserver.ts rename to src/api/Webserver.ts diff --git a/src-ts/api/dimension/DimensionAdminService.ts b/src/api/dimension/DimensionAdminService.ts similarity index 100% rename from src-ts/api/dimension/DimensionAdminService.ts rename to src/api/dimension/DimensionAdminService.ts diff --git a/src-ts/api/dimension/DimensionAppserviceAdminService.ts b/src/api/dimension/DimensionAppserviceAdminService.ts similarity index 100% rename from src-ts/api/dimension/DimensionAppserviceAdminService.ts rename to src/api/dimension/DimensionAppserviceAdminService.ts diff --git a/src-ts/api/dimension/DimensionIntegrationsAdminService.ts b/src/api/dimension/DimensionIntegrationsAdminService.ts similarity index 100% rename from src-ts/api/dimension/DimensionIntegrationsAdminService.ts rename to src/api/dimension/DimensionIntegrationsAdminService.ts diff --git a/src-ts/api/dimension/DimensionIntegrationsService.ts b/src/api/dimension/DimensionIntegrationsService.ts similarity index 100% rename from src-ts/api/dimension/DimensionIntegrationsService.ts rename to src/api/dimension/DimensionIntegrationsService.ts diff --git a/src-ts/api/matrix/MatrixAppServiceApiService.ts b/src/api/matrix/MatrixAppServiceApiService.ts similarity index 100% rename from src-ts/api/matrix/MatrixAppServiceApiService.ts rename to src/api/matrix/MatrixAppServiceApiService.ts diff --git a/src-ts/api/scalar/ScalarService.ts b/src/api/scalar/ScalarService.ts similarity index 100% rename from src-ts/api/scalar/ScalarService.ts rename to src/api/scalar/ScalarService.ts diff --git a/src-ts/api/scalar/ScalarWidgetService.ts b/src/api/scalar/ScalarWidgetService.ts similarity index 100% rename from src-ts/api/scalar/ScalarWidgetService.ts rename to src/api/scalar/ScalarWidgetService.ts diff --git a/src-ts/config.ts b/src/config.ts similarity index 100% rename from src-ts/config.ts rename to src/config.ts diff --git a/src-ts/db/AppserviceStore.ts b/src/db/AppserviceStore.ts similarity index 100% rename from src-ts/db/AppserviceStore.ts rename to src/db/AppserviceStore.ts diff --git a/src-ts/db/DimensionStore.ts b/src/db/DimensionStore.ts similarity index 100% rename from src-ts/db/DimensionStore.ts rename to src/db/DimensionStore.ts diff --git a/src-ts/db/ScalarStore.ts b/src/db/ScalarStore.ts similarity index 100% rename from src-ts/db/ScalarStore.ts rename to src/db/ScalarStore.ts diff --git a/src-ts/db/WidgetStore.ts b/src/db/WidgetStore.ts similarity index 100% rename from src-ts/db/WidgetStore.ts rename to src/db/WidgetStore.ts diff --git a/src-ts/db/migrations/20171218203245-AddTables.ts b/src/db/migrations/20171218203245-AddTables.ts similarity index 100% rename from src-ts/db/migrations/20171218203245-AddTables.ts rename to src/db/migrations/20171218203245-AddTables.ts diff --git a/src-ts/db/migrations/20171218203245-AddWidgets.ts b/src/db/migrations/20171218203245-AddWidgets.ts similarity index 100% rename from src-ts/db/migrations/20171218203245-AddWidgets.ts rename to src/db/migrations/20171218203245-AddWidgets.ts diff --git a/src-ts/db/migrations/20171224122045-AddAppservices.ts b/src/db/migrations/20171224122045-AddAppservices.ts similarity index 100% rename from src-ts/db/migrations/20171224122045-AddAppservices.ts rename to src/db/migrations/20171224122045-AddAppservices.ts diff --git a/src-ts/db/migrations/20171224124645-AddAppserviceUsers.ts b/src/db/migrations/20171224124645-AddAppserviceUsers.ts similarity index 100% rename from src-ts/db/migrations/20171224124645-AddAppserviceUsers.ts rename to src/db/migrations/20171224124645-AddAppserviceUsers.ts diff --git a/src-ts/db/models/AppService.ts b/src/db/models/AppService.ts similarity index 100% rename from src-ts/db/models/AppService.ts rename to src/db/models/AppService.ts diff --git a/src-ts/db/models/AppServiceUser.ts b/src/db/models/AppServiceUser.ts similarity index 100% rename from src-ts/db/models/AppServiceUser.ts rename to src/db/models/AppServiceUser.ts diff --git a/src-ts/db/models/IntegrationRecord.ts b/src/db/models/IntegrationRecord.ts similarity index 100% rename from src-ts/db/models/IntegrationRecord.ts rename to src/db/models/IntegrationRecord.ts diff --git a/src-ts/db/models/Upstream.ts b/src/db/models/Upstream.ts similarity index 100% rename from src-ts/db/models/Upstream.ts rename to src/db/models/Upstream.ts diff --git a/src-ts/db/models/User.ts b/src/db/models/User.ts similarity index 100% rename from src-ts/db/models/User.ts rename to src/db/models/User.ts diff --git a/src-ts/db/models/UserScalarToken.ts b/src/db/models/UserScalarToken.ts similarity index 100% rename from src-ts/db/models/UserScalarToken.ts rename to src/db/models/UserScalarToken.ts diff --git a/src-ts/db/models/WidgetRecord.ts b/src/db/models/WidgetRecord.ts similarity index 100% rename from src-ts/db/models/WidgetRecord.ts rename to src/db/models/WidgetRecord.ts diff --git a/src-ts/index.ts b/src/index.ts similarity index 100% rename from src-ts/index.ts rename to src/index.ts diff --git a/src/integration/generic_types/Bridge.js b/src/integration/generic_types/Bridge.js deleted file mode 100644 index bb1a463..0000000 --- a/src/integration/generic_types/Bridge.js +++ /dev/null @@ -1,22 +0,0 @@ -var IntegrationStub = require("./IntegrationStub"); - -/** - * Represents a bridge. Normally bridges have enhanced configuration and requirements over bots. - */ -class Bridge extends IntegrationStub { - - /** - * Creates a new bridge - * @param bridgeConfig the configuration for the bridge - */ - constructor(bridgeConfig) { - super(bridgeConfig); - } - - /*override*/ - getUserId() { - return null; // bridges don't have bot users we care about - } -} - -module.exports = Bridge; \ No newline at end of file diff --git a/src/integration/generic_types/ComplexBot.js b/src/integration/generic_types/ComplexBot.js deleted file mode 100644 index fd96b46..0000000 --- a/src/integration/generic_types/ComplexBot.js +++ /dev/null @@ -1,18 +0,0 @@ -var IntegrationStub = require("./IntegrationStub"); - -/** - * Represents a bot with additional configuration or setup needs. Normally indicates a bot needs - * more than a simple invite to the room. - */ -class ComplexBot extends IntegrationStub { - - /** - * Creates a new complex bot - * @param botConfig the configuration for the bot - */ - constructor(botConfig) { - super(botConfig); - } -} - -module.exports = ComplexBot; \ No newline at end of file diff --git a/src/integration/generic_types/IntegrationStub.js b/src/integration/generic_types/IntegrationStub.js deleted file mode 100644 index d867532..0000000 --- a/src/integration/generic_types/IntegrationStub.js +++ /dev/null @@ -1,44 +0,0 @@ -/** - * Stub for an Integration - */ -class IntegrationStub { - constructor(botConfig) { - this._config = botConfig; - } - - /** - * Gets the user ID for this bot - * @return {Promise} resolves to the user ID - */ - getUserId() { - return Promise.resolve(this._config.userId); - } - - /** - * Gets state information that represents how this bot is operating. - * @return {Promise<*>} resolves to the state information - */ - getState() { - return Promise.resolve({}); - } - - /** - * Removes the integration from the given room - * @param {string} roomId the room ID to remove the integration from - * @returns {Promise<>} resolves when completed - */ - removeFromRoom(roomId) { - throw new Error("Not implemented"); - } - - /** - * Updates the state information for this integration. The data passed is an implementation detail. - * @param {*} newState the new state - * @returns {Promise<*>} resolves when completed, with the new state of the integration - */ - updateState(newState) { - return Promise.resolve({}); - } -} - -module.exports = IntegrationStub; diff --git a/src/integration/generic_types/Widget.js b/src/integration/generic_types/Widget.js deleted file mode 100644 index f6f18e7..0000000 --- a/src/integration/generic_types/Widget.js +++ /dev/null @@ -1,22 +0,0 @@ -var IntegrationStub = require("./IntegrationStub"); - -/** - * Represents a widget. Widgets allow for web applications or rich functionality within the room. - */ -class Widget extends IntegrationStub { - - /** - * Creates a new widget - * @param widgetConfig the configuration for the widget - */ - constructor(widgetConfig) { - super(widgetConfig); - } - - /*override*/ - getUserId() { - return null; // widgets don't have bot users we care about - } -} - -module.exports = Widget; \ No newline at end of file diff --git a/src/integration/impl/StubbedFactory.js b/src/integration/impl/StubbedFactory.js deleted file mode 100644 index 918e7c0..0000000 --- a/src/integration/impl/StubbedFactory.js +++ /dev/null @@ -1,20 +0,0 @@ -var IntegrationStub = require("../generic_types/IntegrationStub"); - -/** - * Creates an integration using the given - * @param {DimensionStore} db the database - * @param {*} integrationConfig the integration configuration - * @param {string} roomId the room ID - * @param {string} scalarToken the scalar token - * @returns {Promise<*>} resolves to the configured integration - */ -var factory = (db, integrationConfig, roomId, scalarToken) => { - factory.validateConfig(integrationConfig); - return Promise.resolve(new IntegrationStub(integrationConfig)); -}; - -factory.validateConfig = (integrationConfig) => { - // Nothing to do -}; - -module.exports = factory; \ No newline at end of file diff --git a/src/integration/impl/circleci/CircleCiBot.js b/src/integration/impl/circleci/CircleCiBot.js deleted file mode 100644 index 0a70bfd..0000000 --- a/src/integration/impl/circleci/CircleCiBot.js +++ /dev/null @@ -1,53 +0,0 @@ -var ComplexBot = require("../../generic_types/ComplexBot"); - -/** - * Represents a CircleCI bot - */ -class CircleCiBot extends ComplexBot { - - /** - * Creates a new CircleCI bot - * @param botConfig the bot configuration - * @param backbone the backbone powering this bot - */ - constructor(botConfig, backbone) { - super(botConfig); - this._backbone = backbone; - } - - /*override*/ - getUserId() { - return this._backbone.getUserId(); - } - - /*override*/ - getState() { - var response = { - repoTemplates: [], - immutableRepoTemplates: [], - webhookUrl: "" - }; - return this._backbone.getRepos().then(templates => { - response.repoTemplates = templates; - return this._backbone.getImmutableRepos(); - }).then(immutable => { - response.immutableRepoTemplates = immutable; - return this._backbone.getWebhookUrl(); - }).then(url => { - response.webhookUrl = url; - return response; - }); - } - - /*override*/ - removeFromRoom(roomId) { - return this._backbone.removeFromRoom(roomId); - } - - /*override*/ - updateState(newState) { - return this._backbone.setRepos(newState.repoTemplates).then(() => this.getState()); - } -} - -module.exports = CircleCiBot; \ No newline at end of file diff --git a/src/integration/impl/circleci/CircleCiFactory.js b/src/integration/impl/circleci/CircleCiFactory.js deleted file mode 100644 index c3e7fa7..0000000 --- a/src/integration/impl/circleci/CircleCiFactory.js +++ /dev/null @@ -1,20 +0,0 @@ -var CircleCiBot = require("./CircleCiBot"); -var VectorCircleCiBackbone = require("./VectorCircleCiBackbone"); -var UpstreamConfiguration = require("../../../UpstreamConfiguration"); - -var factory = (db, integrationConfig, roomId, scalarToken) => { - factory.validateConfig(integrationConfig); - - return db.getUpstreamToken(scalarToken).then(upstreamToken => { - var backbone = new VectorCircleCiBackbone(roomId, upstreamToken); - return new CircleCiBot(integrationConfig, backbone); - }); -}; - -factory.validateConfig = (integrationConfig) => { - if (!integrationConfig.upstream) throw new Error("Unsupported configuration"); - if (integrationConfig.upstream.type !== "vector") throw new Error("Unsupported upstream"); - if (!UpstreamConfiguration.hasUpstream("vector")) throw new Error("Vector upstream not specified"); -}; - -module.exports = factory; \ No newline at end of file diff --git a/src/integration/impl/circleci/StubbedCircleCiBackbone.js b/src/integration/impl/circleci/StubbedCircleCiBackbone.js deleted file mode 100644 index 0a454db..0000000 --- a/src/integration/impl/circleci/StubbedCircleCiBackbone.js +++ /dev/null @@ -1,63 +0,0 @@ -/** - * Stubbed/placeholder CircleCI backbone - */ -class StubbedCircleCiBackbone { - - /** - * Creates a new stubbed CircleCI backbone - */ - constructor() { - } - - /** - * Gets the user ID for this backbone - * @returns {Promise} resolves to the user ID - */ - getUserId() { - throw new Error("Not implemented"); - } - - /** - * Gets the repository templates for this backbone - * @returns {Promise<{repoKey:string,template:string}[]>} resolves to the collection of repositories and their templates - */ - getRepos() { - throw new Error("Not implemented"); - } - - /** - * Gets the immutable repository templates for this backbone (set by other users) - * @returns {Promise<{repoKey:string,template:string,ownerId:string}[]>} resolves to the collection of repositories and their templates - */ - getImmutableRepos() { - throw new Error("Not implemented"); - } - - /** - * Sets the new repository templates for this backbone - * @param {{repoKey:string,template:string}[]} newRepos the new templates for the repositories - * @returns {Promise<>} resolves when complete - */ - setRepos(newRepos) { - throw new Error("Not implemented"); - } - - /** - * Gets the webhook url for this backbone - * @returns {Promise} resolves to the webhook URL - */ - getWebhookUrl() { - throw new Error("Not implemented"); - } - - /** - * Removes the bot from the given room - * @param {string} roomId the room ID to remove the bot from - * @returns {Promise<>} resolves when completed - */ - removeFromRoom(roomId) { - throw new Error("Not implemented"); - } -} - -module.exports = StubbedCircleCiBackbone; \ No newline at end of file diff --git a/src/integration/impl/circleci/VectorCircleCiBackbone.js b/src/integration/impl/circleci/VectorCircleCiBackbone.js deleted file mode 100644 index 9b3ee4a..0000000 --- a/src/integration/impl/circleci/VectorCircleCiBackbone.js +++ /dev/null @@ -1,108 +0,0 @@ -var StubbedCircleCiBackbone = require("./StubbedCircleCiBackbone"); -var VectorScalarClient = require("../../../scalar/VectorScalarClient"); -var _ = require("lodash"); -var log = require("../../../util/LogService"); - -/** - * Backbone for CircleCI bots running on vector.im through scalar - */ -class VectorCircleCiBackbone extends StubbedCircleCiBackbone { - - /** - * Creates a new Vector CircleCI backbone - * @param {string} roomId the room ID to manage - * @param {string} upstreamScalarToken the vector scalar token - */ - constructor(roomId, upstreamScalarToken) { - super(); - this._roomId = roomId; - this._scalarToken = upstreamScalarToken; - this._info = null; - this._otherTemplates = []; - } - - /*override*/ - getUserId() { - return (this._info ? Promise.resolve() : this._getInfo()).then(() => { - return this._info.bot_user_id; - }); - } - - /*override*/ - getRepos() { - return (this._info ? Promise.resolve() : this._getInfo()).then(() => { - if (this._info.integrations.length == 0) return []; - - var rooms = _.keys(this._info.integrations[0].config.rooms); - if (rooms.indexOf(this._roomId) === -1) return []; - - var repos = _.keys(this._info.integrations[0].config.rooms[this._roomId].repos); - return _.map(repos, r => { - return {repoKey: r, template: this._info.integrations[0].config.rooms[this._roomId].repos[r].template}; - }); - }); - } - - /*override*/ - getImmutableRepos() { - return (this._info ? Promise.resolve() : this._getInfo()).then(() => { - return this._otherTemplates; - }); - } - - /*override*/ - setRepos(newRepos) { - var config = {}; - config[this._roomId] = {repos: {}}; - for (var repo of newRepos) config[this._roomId].repos[repo.repoKey] = {template: repo.template}; - - return VectorScalarClient.configureIntegration("circleci", this._scalarToken, { - rooms: config - }); - } - - /*override*/ - getWebhookUrl() { - // string - return (this._info ? Promise.resolve() : this._getInfo()).then(() => { - if (this._info.integrations.length == 0) return ""; - return this._info.integrations[0].config.webhook_url; - }); - } - - _getInfo() { - return VectorScalarClient.getIntegrationsForRoom(this._roomId, this._scalarToken).then(integrations => { - this._otherTemplates = []; - for (var integration of integrations) { - if (integration.self) continue; // skip - we're not looking for ones we know about - if (integration.type == "circleci") { - var roomIds = _.keys(integration.config.rooms); - if (roomIds.length === 0) continue; - if (roomIds.length !== 1) log.warn("VectorCircleCiBackbone", "Expected 1 room but found " + roomIds.length); - - var roomConfig = integration.config.rooms[roomIds[0]]; - var repositories = _.keys(roomConfig.repos); - - for (var repo of repositories) { - this._otherTemplates.push({ - repoKey: repo, - template: roomConfig.repos[repo].template, - ownerId: integration.user_id - }); - } - } - } - - return VectorScalarClient.getIntegration("circleci", this._roomId, this._scalarToken); - }).then(info => { - this._info = info; - }); - } - - /*override*/ - removeFromRoom(roomId) { - return VectorScalarClient.removeIntegration("circleci", roomId, this._scalarToken); - } -} - -module.exports = VectorCircleCiBackbone; \ No newline at end of file diff --git a/src/integration/impl/index.js b/src/integration/impl/index.js deleted file mode 100644 index 92d7e9b..0000000 --- a/src/integration/impl/index.js +++ /dev/null @@ -1,46 +0,0 @@ -var log = require("../../util/LogService"); -var StubbedFactory = require("./StubbedFactory"); -var SimpleBotFactory = require("./simple_bot/SimpleBotFactory"); -var RSSFactory = require("./rss/RSSFactory"); -var IRCFactory = require("./irc/IRCFactory"); -var TravisCiFactory = require("./travisci/TravisCiFactory"); -var CircleCiFactory = require("./circleci/CircleCiFactory"); -var SimpleWidgetFactory = require("./simple_widget/SimpleWidgetFactory"); - -var mapping = { - "complex-bot": { - "rss": RSSFactory, - "travisci": TravisCiFactory, - "circleci": CircleCiFactory, - }, - "bridge": { - "irc": IRCFactory, - } -}; - -var defaultFactories = { - "complex-bot": null, - "bot": SimpleBotFactory, - "bridge": null, - "widget": SimpleWidgetFactory, -}; - -module.exports = { - getFactory: (integrationConfig) => { - var opts = mapping[integrationConfig.type]; - - if (!opts) { - log.verbose("IntegrationImpl", "No option set available for " + integrationConfig.type + " - will attempt defaults"); - } - - var factory = null; - if (!opts) factory = defaultFactories[integrationConfig.type]; - else factory = opts[integrationConfig.integrationType]; - if (!factory) { - log.verbose("IntegrationImpl", "No factory available for " + integrationConfig.type + " (" + integrationConfig.integrationType + ") - using stub"); - factory = StubbedFactory; - } - - return factory; - } -}; \ No newline at end of file diff --git a/src/integration/impl/irc/IRCApi.js b/src/integration/impl/irc/IRCApi.js deleted file mode 100644 index aed963d..0000000 --- a/src/integration/impl/irc/IRCApi.js +++ /dev/null @@ -1,114 +0,0 @@ -var Integrations = require("../../index"); -var IntegrationImpl = require("../index"); -var log = require("../../../util/LogService"); - -/** - * API Handler for the IRC integration - */ -class IRCApi { - - /** - * Creates a new IRC API - */ - constructor() { - } - - /** - * Bootstraps the IRC API - * @param {*} app the Express application - * @param {DimensionStore} db the store to use - */ - bootstrap(app, db) { - if (!Integrations.byType["bridge"] || !Integrations.byType["bridge"]["irc"]) { - log.info("IRCApi", "IRC Bridge not enabled - not setting up the API"); - return; - } else log.info("IRCApi", "Setting up IRC API"); - - this._db = db; - - app.get("/api/v1/irc/:roomId/ops/:network/:channel", this._getChannelOps.bind(this)); - app.put("/api/v1/irc/:roomId/channels/:network/:channel", this._addChannel.bind(this)); - app.delete("/api/v1/irc/:roomId/channels/:network/:channel", this._deleteChannel.bind(this)); - } - - _getChannelOps(req, res) { - this._generalProcessing(req, res).then(ircBridge => { - var network = req.params.network; - var channel = req.params.channel; - return ircBridge.getChannelOps(network, channel).catch(err => { - log.error("IRCApi", err); - console.error(err); - res.status(500).send({error: err}); - return null; - }); - }).then(ops => { - if (ops !== null) res.status(200).send(ops); - }).catch(() => null); - } - - _addChannel(req, res) { - this._generalProcessing(req, res).then(ircBridge => { - var network = req.params.network; - var channel = req.params.channel; - var op = req.query.op; - return ircBridge.addChannel(network, channel, op).catch(err => { - log.error("IRCApi", err); - console.error(err); - res.status(500).send({error: err}); - return null; - }); - }).then(result => { - if (result !== null) res.status(200).send({successful: true}); - }).catch(() => null); - } - - _deleteChannel(req, res) { - this._generalProcessing(req, res).then(ircBridge => { - var network = req.params.network; - var channel = req.params.channel; - return ircBridge.removeChannel(network, channel).catch(err => { - log.error("IRCApi", err); - console.error(err); - res.status(500).send({error: err}); - return null; - }); - }).then(result => { - if (result !== null) res.status(200).send({successful: true}); - }).catch(() => null); - } - - _generalProcessing(req, res) { - return new Promise((resolve, reject) => { - res.setHeader("Content-Type", "application/json"); - - var roomId = req.params.roomId; - var network = req.params.network; - var channel = req.params.channel; - if (!roomId || !network || !channel) { - res.status(400).send({error: 'Missing room ID, network, or channel'}); - reject(); - return; - } - - var scalarToken = req.query.scalar_token; - this._db.checkToken(scalarToken).then(() => { - var conf = Integrations.byType["bridge"]["irc"]; - var factory = IntegrationImpl.getFactory(conf); - factory(this._db, conf, roomId, scalarToken).then(resolve).catch(err => { - log.error("IRCApi", err); - console.error(err); - res.status(500).send({error: err}); - reject(); - }); - }).catch(err => { - log.error("IRCApi", err); - console.error(err); - res.status(500).send({error: err}); - reject(); - }); - }); - } - -} - -module.exports = new IRCApi(); \ No newline at end of file diff --git a/src/integration/impl/irc/IRCBridge.js b/src/integration/impl/irc/IRCBridge.js deleted file mode 100644 index 95a20bc..0000000 --- a/src/integration/impl/irc/IRCBridge.js +++ /dev/null @@ -1,75 +0,0 @@ -var Bridge = require("../../generic_types/Bridge"); - -/** - * Represents an IRC bridge - */ -class IRCBridge extends Bridge { - - /** - * Creates a new IRC bridge - * @param bridgeConfig the bridge configuration - * @param backbone the backbone powering this bridge - */ - constructor(bridgeConfig, backbone) { - super(bridgeConfig); - this._backbone = backbone; - } - - /*override*/ - getState() { - var response = { - availableNetworks: [], - channels: {} - }; - return this._backbone.getNetworks().then(networks => { - response.availableNetworks = networks; - return this._backbone.getLinkedChannels(); - }).then(channels => { - response.channels = channels; - return response; - }); - } - - /*override*/ - removeFromRoom(roomId) { - return this._backbone.removeFromRoom(roomId); - } - - /*override*/ - updateState(newState) { - throw new Error("State cannot be updated for an IRC bridge. Use the IRC API instead."); - } - - /** - * Gets a list of operators available in a particular channel on a particular network - * @param {string} network the network to look at - * @param {string} channel the channel to look in (without prefixed #) - * @returns {Promise} resolves to a list of operators - */ - getChannelOps(network, channel) { - return this._backbone.getChannelOps(network, channel); - } - - /** - * Links a channel to the room this bridge controls - * @param {string} network the network to link to - * @param {string} channel the channel to link to - * @param {string} op the channel operator to request permission from - * @returns {Promise<>} resolves when complete - */ - addChannel(network, channel, op) { - return this._backbone.addChannel(network, channel, op); - } - - /** - * Unlinks a channel from the room this bridge controls - * @param {string} network the network to unlink from - * @param {string} channel the channel to unlink - * @returns {Promise<>} resolves when complete - */ - removeChannel(network, channel) { - return this._backbone.removeChannel(network, channel); - } -} - -module.exports = IRCBridge; \ No newline at end of file diff --git a/src/integration/impl/irc/IRCFactory.js b/src/integration/impl/irc/IRCFactory.js deleted file mode 100644 index 131d729..0000000 --- a/src/integration/impl/irc/IRCFactory.js +++ /dev/null @@ -1,20 +0,0 @@ -var IRCBridge = require("./IRCBridge"); -var VectorIrcBackbone = require("./VectorIrcBackbone"); -var UpstreamConfiguration = require("../../../UpstreamConfiguration"); - -var factory = (db, integrationConfig, roomId, scalarToken) => { - factory.validateConfig(integrationConfig); - - return db.getUpstreamToken(scalarToken).then(upstreamToken => { - var backbone = new VectorIrcBackbone(roomId, upstreamToken); - return new IRCBridge(integrationConfig, backbone); - }); -}; - -factory.validateConfig = (integrationConfig) => { - if (!integrationConfig.upstream) throw new Error("Unsupported configuration"); - if (integrationConfig.upstream.type !== "vector") throw new Error("Unsupported upstream"); - if (!UpstreamConfiguration.hasUpstream("vector")) throw new Error("Vector upstream not specified"); -}; - -module.exports = factory; \ No newline at end of file diff --git a/src/integration/impl/irc/StubbedIrcBackbone.js b/src/integration/impl/irc/StubbedIrcBackbone.js deleted file mode 100644 index 2b323d1..0000000 --- a/src/integration/impl/irc/StubbedIrcBackbone.js +++ /dev/null @@ -1,60 +0,0 @@ -/** - * Stubbed/placeholder IRC backbone - */ -class StubbedIrcBackbone { - - /** - * Creates a new stubbed IRC backbone - */ - constructor() { - } - - /** - * Gets a list of all available networks - * @returns {Promise<{name: string, id: string}[]>} resolves to the list of available networks - */ - getNetworks() { - return Promise.resolve([]); - } - - /** - * Gets a network representation of the linked channels - * @returns {Promise<{[string]: string[]}>} resolves to the network representation of linked channels - */ - getLinkedChannels() { - return Promise.resolve({}); - } - - /** - * Gets a list of operators available in a particular channel on a particular network - * @param {string} network the network to look at - * @param {string} channel the channel to look in (without prefixed #) - * @returns {Promise} resolves to a list of operators - */ - getChannelOps(network, channel) { - return Promise.resolve([]); - } - - /** - * Links a channel to the room this backbone controls - * @param {string} network the network to link to - * @param {string} channel the channel to link to - * @param {string} op the channel operator to request permission from - * @returns {Promise<>} resolves when complete - */ - addChannel(network, channel, op) { - throw new Error("Not implemented"); - } - - /** - * Unlinks a channel from the room this backbone controls - * @param {string} network the network to unlink from - * @param {string} channel the channel to unlink - * @returns {Promise<>} resolves when complete - */ - removeChannel(network, channel) { - throw new Error("Not implemented"); - } -} - -module.exports = StubbedIrcBackbone; \ No newline at end of file diff --git a/src/integration/impl/irc/VectorIrcBackbone.js b/src/integration/impl/irc/VectorIrcBackbone.js deleted file mode 100644 index 65165ae..0000000 --- a/src/integration/impl/irc/VectorIrcBackbone.js +++ /dev/null @@ -1,120 +0,0 @@ -var StubbedIrcBackbone = require("./StubbedIrcBackbone"); -var VectorScalarClient = require("../../../scalar/VectorScalarClient"); -var _ = require("lodash"); -var log = require("../../../util/LogService"); - -/** - * Backbone for IRC bridges running on vector.im through scalar - */ -class VectorIrcBackbone extends StubbedIrcBackbone { - - /** - * Creates a new Vector IRC backbone - * @param {string} roomId the room ID to manage - * @param {string} upstreamScalarToken the vector scalar token - */ - constructor(roomId, upstreamScalarToken) { - super(); - this._roomId = roomId; - this._scalarToken = upstreamScalarToken; - this._lastNetworkResponse = null; - } - - /*override*/ - getNetworks() { - return this._getNetworks().then(networks => _.map(networks, n => { - return {name: n.title, id: n.id}; - })); - } - - /*override*/ - getLinkedChannels() { - var networks; - return this._getNetworks().then(n => { - networks = n; - return VectorScalarClient.getIrcLinks(this._roomId, this._scalarToken); - }).then(links => { - var container = {}; - - var ridToServerId = {}; - - for (var network of networks) { - ridToServerId[network.rid] = network.id; - container[network.id] = []; - } - - for (var link of links) { - var server = ridToServerId[link.rid]; - if (!server) { - log.error("VectorIrcBackbone", "Could not find network for RID " + link.rid); - throw new Error("Unexpected RID"); - } - - container[server].push(link.channel); - } - - return container; - }); - } - - /*override*/ - getChannelOps(network, channel) { - return this._getNetworks().then(networks => { - var networkServer = null; - var rid = null; - for (var n of networks) { - if (n.id === network) { - networkServer = n.domain; - rid = n.rid; - break; - } - } - - return VectorScalarClient.getIrcOperators(rid, networkServer, '#' + channel, this._scalarToken); - }); - } - - /*override*/ - addChannel(network, channel, op) { - return this._getNetworks().then(networks => { - var networkServer = null; - var rid = null; - for (var n of networks) { - if (n.id === network) { - networkServer = n.domain; - rid = n.rid; - break; - } - } - - return VectorScalarClient.addIrcLink(rid, this._roomId, networkServer, '#' + channel, op, this._scalarToken); - }); - } - - /*override*/ - removeChannel(network, channel) { - return this._getNetworks().then(networks => { - var networkServer = null; - var rid = null; - for (var n of networks) { - if (n.id === network) { - networkServer = n.domain; - rid = n.rid; - break; - } - } - - return VectorScalarClient.removeIrcLink(rid, this._roomId, networkServer, '#' + channel, this._scalarToken); - }); - } - - _getNetworks() { - if (this._lastNetworkResponse !== null) return Promise.resolve(this._lastNetworkResponse); - return VectorScalarClient.getIrcNetworks(this._scalarToken).then(networks => { - this._lastNetworkResponse = networks; - return networks; - }); - } -} - -module.exports = VectorIrcBackbone; \ No newline at end of file diff --git a/src/integration/impl/rss/RSSBot.js b/src/integration/impl/rss/RSSBot.js deleted file mode 100644 index f3384b2..0000000 --- a/src/integration/impl/rss/RSSBot.js +++ /dev/null @@ -1,49 +0,0 @@ -var ComplexBot = require("../../generic_types/ComplexBot"); - -/** - * Represents an RSS bot - */ -class RSSBot extends ComplexBot { - - /** - * Creates a new RSS bot - * @param botConfig the bot configuration - * @param backbone the backbone powering this bot - */ - constructor(botConfig, backbone) { - super(botConfig); - this._backbone = backbone; - } - - /*override*/ - getUserId() { - return this._backbone.getUserId(); - } - - /*override*/ - getState() { - var response = { - feeds: [], - immutableFeeds: [] - }; - return this._backbone.getFeeds().then(feeds => { - response.feeds = feeds; - return this._backbone.getImmutableFeeds(); - }).then(feeds => { - response.immutableFeeds = feeds; - return response; - }); - } - - /*override*/ - removeFromRoom(roomId) { - return this._backbone.removeFromRoom(roomId); - } - - /*override*/ - updateState(newState) { - return this._backbone.setFeeds(newState.feeds).then(() => this.getState()); - } -} - -module.exports = RSSBot; \ No newline at end of file diff --git a/src/integration/impl/rss/RSSFactory.js b/src/integration/impl/rss/RSSFactory.js deleted file mode 100644 index f800a7b..0000000 --- a/src/integration/impl/rss/RSSFactory.js +++ /dev/null @@ -1,20 +0,0 @@ -var RSSBot = require("./RSSBot"); -var VectorRssBackbone = require("./VectorRssBackbone"); -var UpstreamConfiguration = require("../../../UpstreamConfiguration"); - -var factory = (db, integrationConfig, roomId, scalarToken) => { - factory.validateConfig(integrationConfig); - - return db.getUpstreamToken(scalarToken).then(upstreamToken => { - var backbone = new VectorRssBackbone(roomId, upstreamToken); - return new RSSBot(integrationConfig, backbone); - }); -}; - -factory.validateConfig = (integrationConfig) => { - if (!integrationConfig.upstream) throw new Error("Unsupported configuration"); - if (integrationConfig.upstream.type !== "vector") throw new Error("Unsupported upstream"); - if (!UpstreamConfiguration.hasUpstream("vector")) throw new Error("Vector upstream not specified"); -}; - -module.exports = factory; \ No newline at end of file diff --git a/src/integration/impl/rss/StubbedRssBackbone.js b/src/integration/impl/rss/StubbedRssBackbone.js deleted file mode 100644 index 6e51205..0000000 --- a/src/integration/impl/rss/StubbedRssBackbone.js +++ /dev/null @@ -1,55 +0,0 @@ -/** - * Stubbed/placeholder RSS backbone - */ -class StubbedRssBackbone { - - /** - * Creates a new stubbed RSS backbone - */ - constructor() { - } - - /** - * Gets the user ID for this backbone - * @returns {Promise} resolves to the user ID - */ - getUserId() { - throw new Error("Not implemented"); - } - - /** - * Gets the feeds for this backbone - * @returns {Promise} resolves to the collection of feeds - */ - getFeeds() { - throw new Error("Not implemented"); - } - - /** - * Sets the new feeds for this backbone - * @param {string[]} newFeeds the new feed URLs - * @returns {Promise<>} resolves when complete - */ - setFeeds(newFeeds) { - throw new Error("Not implemented"); - } - - /** - * Gets the immutable feeds for this backbone - * @returns {Promise<{url:string,ownerId:string}>} resolves to the collection of immutable feeds - */ - getImmutableFeeds() { - throw new Error("Not implemented"); - } - - /** - * Removes the bot from the given room - * @param {string} roomId the room ID to remove the bot from - * @returns {Promise<>} resolves when completed - */ - removeFromRoom(roomId) { - throw new Error("Not implemented"); - } -} - -module.exports = StubbedRssBackbone; \ No newline at end of file diff --git a/src/integration/impl/rss/VectorRssBackbone.js b/src/integration/impl/rss/VectorRssBackbone.js deleted file mode 100644 index d4a37f6..0000000 --- a/src/integration/impl/rss/VectorRssBackbone.js +++ /dev/null @@ -1,82 +0,0 @@ -var StubbedRssBackbone = require("./StubbedRssBackbone"); -var VectorScalarClient = require("../../../scalar/VectorScalarClient"); -var _ = require("lodash"); -var log = require("../../../util/LogService"); - -/** - * Backbone for RSS bots running on vector.im through scalar - */ -class VectorRssBackbone extends StubbedRssBackbone { - - /** - * Creates a new Vector RSS backbone - * @param {string} roomId the room ID to manage - * @param {string} upstreamScalarToken the vector scalar token - */ - constructor(roomId, upstreamScalarToken) { - super(); - this._roomId = roomId; - this._scalarToken = upstreamScalarToken; - this._info = null; - this._otherFeeds = []; - } - - /*override*/ - getUserId() { - return (this._info ? Promise.resolve() : this._getInfo()).then(() => { - return this._info.bot_user_id; - }); - } - - /*override*/ - getFeeds() { - return (this._info ? Promise.resolve() : this._getInfo()).then(() => { - if (this._info.integrations.length == 0) return []; - return _.keys(this._info.integrations[0].config.feeds); - }); - } - - /*override*/ - setFeeds(newFeeds) { - var feedConfig = {}; - for (var feed of newFeeds) feedConfig[feed] = {}; - - return VectorScalarClient.configureIntegration("rssbot", this._scalarToken, { - feeds: feedConfig, - room_id: this._roomId - }); - } - - /*override*/ - getImmutableFeeds() { - return (this._info ? Promise.resolve() : this._getInfo()).then(() => { - return this._otherFeeds; - }); - } - - _getInfo() { - return VectorScalarClient.getIntegrationsForRoom(this._roomId, this._scalarToken).then(integrations => { - this._otherFeeds = []; - for (var integration of integrations) { - if (integration.self) continue; // skip - we're not looking for ones we know about - if (integration.type == "rssbot") { - var urls = _.keys(integration.config.feeds); - for (var url of urls) { - this._otherFeeds.push({url: url, ownerId: integration.user_id}); - } - } - } - - return VectorScalarClient.getIntegration("rssbot", this._roomId, this._scalarToken); - }).then(info => { - this._info = info; - }); - } - - /*override*/ - removeFromRoom(roomId) { - return VectorScalarClient.removeIntegration("rssbot", roomId, this._scalarToken); - } -} - -module.exports = VectorRssBackbone; \ No newline at end of file diff --git a/src/integration/impl/simple_bot/HostedSimpleBackbone.js b/src/integration/impl/simple_bot/HostedSimpleBackbone.js deleted file mode 100644 index ce10929..0000000 --- a/src/integration/impl/simple_bot/HostedSimpleBackbone.js +++ /dev/null @@ -1,31 +0,0 @@ -var sdk = require("matrix-js-sdk"); -var log = require("../../../util/LogService"); -var StubbedSimpleBackbone = require("./StubbedSimpleBackbone"); - -/** - * Standalone (matrix) backbone for simple bots - */ -class HostedSimpleBackbone extends StubbedSimpleBackbone { - - /** - * Creates a new standalone bot backbone - * @param {*} botConfig the configuration for the bot - */ - constructor(botConfig) { - super(botConfig); - this._config = botConfig; - this._client = sdk.createClient({ - baseUrl: this._config.hosted.homeserverUrl, - accessToken: this._config.hosted.accessToken, - userId: this._config.userId, - }); - } - - /*override*/ - removeFromRoom(roomId) { - log.info("HostedSimpleBackbone", "Removing " + this._config.userId + " from " + roomId); - return this._client.leave(roomId); - } -} - -module.exports = HostedSimpleBackbone; \ No newline at end of file diff --git a/src/integration/impl/simple_bot/SimpleBot.js b/src/integration/impl/simple_bot/SimpleBot.js deleted file mode 100644 index 08cffbd..0000000 --- a/src/integration/impl/simple_bot/SimpleBot.js +++ /dev/null @@ -1,24 +0,0 @@ -var IntegrationStub = require("../../generic_types/IntegrationStub"); - -/** - * Represents an RSS bot - */ -class SimpleBot extends IntegrationStub { - - /** - * Creates a new RSS bot - * @param botConfig the bot configuration - * @param backbone the backbone powering this bot - */ - constructor(botConfig, backbone) { - super(botConfig); - this._backbone = backbone; - } - - /*override*/ - removeFromRoom(roomId) { - return this._backbone.removeFromRoom(roomId); - } -} - -module.exports = SimpleBot; \ No newline at end of file diff --git a/src/integration/impl/simple_bot/SimpleBotFactory.js b/src/integration/impl/simple_bot/SimpleBotFactory.js deleted file mode 100644 index 1c4c1cc..0000000 --- a/src/integration/impl/simple_bot/SimpleBotFactory.js +++ /dev/null @@ -1,27 +0,0 @@ -var SimpleBot = require("./SimpleBot"); -var VectorSimpleBackbone = require("./VectorSimpleBackbone"); -var HostedSimpleBackbone = require("./HostedSimpleBackbone"); -var UpstreamConfiguration = require("../../../UpstreamConfiguration"); - -var factory = (db, integrationConfig, roomId, scalarToken) => { - factory.validateConfig(integrationConfig); - - if (integrationConfig.upstream) { - return db.getUpstreamToken(scalarToken).then(upstreamToken => { - var backbone = new VectorSimpleBackbone(integrationConfig, upstreamToken); - return new SimpleBot(integrationConfig, backbone); - }); - } else if (integrationConfig.hosted) { - var backbone = new HostedSimpleBackbone(integrationConfig); - return Promise.resolve(new SimpleBot(integrationConfig, backbone)); - } -}; - -factory.validateConfig = (integrationConfig) => { - if (integrationConfig.upstream) { - if (integrationConfig.upstream.type !== "vector") throw new Error("Unsupported upstream"); - if (!UpstreamConfiguration.hasUpstream("vector")) throw new Error("Vector upstream not specified"); - } else if (!integrationConfig.hosted) throw new Error("Unsupported configuration"); -}; - -module.exports = factory; \ No newline at end of file diff --git a/src/integration/impl/simple_bot/StubbedSimpleBackbone.js b/src/integration/impl/simple_bot/StubbedSimpleBackbone.js deleted file mode 100644 index a864912..0000000 --- a/src/integration/impl/simple_bot/StubbedSimpleBackbone.js +++ /dev/null @@ -1,24 +0,0 @@ -/** - * Stubbed backbone for simple bots - */ -class StubbedSimpleBackbone { - - /** - * Creates a new stubbed bot backbone - * @param {*} botConfig the configuration for the bot - */ - constructor(botConfig) { - this._config = botConfig; - } - - /** - * Leaves a given Matrix room - * @param {string} roomId the room to leave - * @returns {Promise<>} resolves when completed - */ - removeFromRoom(roomId) { - throw new Error("Not implemented"); - } -} - -module.exports = StubbedSimpleBackbone; \ No newline at end of file diff --git a/src/integration/impl/simple_bot/VectorSimpleBackbone.js b/src/integration/impl/simple_bot/VectorSimpleBackbone.js deleted file mode 100644 index 2d8fcfc..0000000 --- a/src/integration/impl/simple_bot/VectorSimpleBackbone.js +++ /dev/null @@ -1,28 +0,0 @@ -var VectorScalarClient = require("../../../scalar/VectorScalarClient"); -var log = require("../../../util/LogService"); -var StubbedSimpleBackbone = require("./StubbedSimpleBackbone"); - -/** - * Vector backbone for simple bots - */ -class VectorSimpleBackbone extends StubbedSimpleBackbone { - - /** - * Creates a new vector bot backbone - * @param {*} botConfig the configuration for the bot - * @param {string} upstreamScalarToken the upstream scalar token - */ - constructor(botConfig, upstreamScalarToken) { - super(botConfig); - this._config = botConfig; - this._upstreamToken = upstreamScalarToken; - } - - /*override*/ - removeFromRoom(roomId) { - log.info("VectorSimpleBackbone", "Removing " + this._config.userId + " from " + roomId); - return VectorScalarClient.removeIntegration(this._config.upstream.id, roomId, this._upstreamToken); - } -} - -module.exports = VectorSimpleBackbone; \ No newline at end of file diff --git a/src/integration/impl/simple_widget/SimpleWidget.js b/src/integration/impl/simple_widget/SimpleWidget.js deleted file mode 100644 index b916d6b..0000000 --- a/src/integration/impl/simple_widget/SimpleWidget.js +++ /dev/null @@ -1,17 +0,0 @@ -var Widget = require("../../generic_types/Widget"); - -/** - * Represents a simple widget - */ -class SimpleWidget extends Widget { - - /** - * Creates a new simple widget - * @param widgetConfig the widget configuration - */ - constructor(widgetConfig) { - super(widgetConfig); - } -} - -module.exports = SimpleWidget; \ No newline at end of file diff --git a/src/integration/impl/simple_widget/SimpleWidgetFactory.js b/src/integration/impl/simple_widget/SimpleWidgetFactory.js deleted file mode 100644 index 34782e0..0000000 --- a/src/integration/impl/simple_widget/SimpleWidgetFactory.js +++ /dev/null @@ -1,13 +0,0 @@ -var SimpleWidget = require("./SimpleWidget"); -var Promise = require("bluebird"); - -var factory = (db, integrationConfig, roomId, scalarToken) => { - factory.validateConfig(integrationConfig); - return Promise.resolve(new SimpleWidget(integrationConfig, roomId)); -}; - -factory.validateConfig = (integrationConfig) => { - // Nothing to do -}; - -module.exports = factory; \ No newline at end of file diff --git a/src/integration/impl/travisci/StubbedTravisCiBackbone.js b/src/integration/impl/travisci/StubbedTravisCiBackbone.js deleted file mode 100644 index 58b60c1..0000000 --- a/src/integration/impl/travisci/StubbedTravisCiBackbone.js +++ /dev/null @@ -1,63 +0,0 @@ -/** - * Stubbed/placeholder Travis CI backbone - */ -class StubbedTravisCiBackbone { - - /** - * Creates a new stubbed RSS backbone - */ - constructor() { - } - - /** - * Gets the user ID for this backbone - * @returns {Promise} resolves to the user ID - */ - getUserId() { - throw new Error("Not implemented"); - } - - /** - * Gets the repository templates for this backbone - * @returns {Promise<{repoKey:string,template:string}[]>} resolves to the collection of repositories and their templates - */ - getRepos() { - throw new Error("Not implemented"); - } - - /** - * Gets the immutable repository templates for this backbone (set by other users) - * @returns {Promise<{repoKey:string,template:string,ownerId:string}[]>} resolves to the collection of repositories and their templates - */ - getImmutableRepos() { - throw new Error("Not implemented"); - } - - /** - * Sets the new repository templates for this backbone - * @param {{repoKey:string,template:string}[]} newRepos the new templates for the repositories - * @returns {Promise<>} resolves when complete - */ - setRepos(newRepos) { - throw new Error("Not implemented"); - } - - /** - * Gets the webhook url for this backbone - * @returns {Promise} resolves to the webhook URL - */ - getWebhookUrl() { - throw new Error("Not implemented"); - } - - /** - * Removes the bot from the given room - * @param {string} roomId the room ID to remove the bot from - * @returns {Promise<>} resolves when completed - */ - removeFromRoom(roomId) { - throw new Error("Not implemented"); - } -} - -module.exports = StubbedTravisCiBackbone; \ No newline at end of file diff --git a/src/integration/impl/travisci/TravisCiBot.js b/src/integration/impl/travisci/TravisCiBot.js deleted file mode 100644 index dbedbed..0000000 --- a/src/integration/impl/travisci/TravisCiBot.js +++ /dev/null @@ -1,53 +0,0 @@ -var ComplexBot = require("../../generic_types/ComplexBot"); - -/** - * Represents a Travis CI bot - */ -class TravisCiBot extends ComplexBot { - - /** - * Creates a new Travis CI bot - * @param botConfig the bot configuration - * @param backbone the backbone powering this bot - */ - constructor(botConfig, backbone) { - super(botConfig); - this._backbone = backbone; - } - - /*override*/ - getUserId() { - return this._backbone.getUserId(); - } - - /*override*/ - getState() { - var response = { - repoTemplates: [], - immutableRepoTemplates: [], - webhookUrl: "" - }; - return this._backbone.getRepos().then(templates => { - response.repoTemplates = templates; - return this._backbone.getImmutableRepos(); - }).then(immutable => { - response.immutableRepoTemplates = immutable; - return this._backbone.getWebhookUrl(); - }).then(url => { - response.webhookUrl = url; - return response; - }); - } - - /*override*/ - removeFromRoom(roomId) { - return this._backbone.removeFromRoom(roomId); - } - - /*override*/ - updateState(newState) { - return this._backbone.setRepos(newState.repoTemplates).then(() => this.getState()); - } -} - -module.exports = TravisCiBot; \ No newline at end of file diff --git a/src/integration/impl/travisci/TravisCiFactory.js b/src/integration/impl/travisci/TravisCiFactory.js deleted file mode 100644 index 42ac8e9..0000000 --- a/src/integration/impl/travisci/TravisCiFactory.js +++ /dev/null @@ -1,20 +0,0 @@ -var TravisCiBot = require("./TravisCiBot"); -var VectorTravisCiBackbone = require("./VectorTravisCiBackbone"); -var UpstreamConfiguration = require("../../../UpstreamConfiguration"); - -var factory = (db, integrationConfig, roomId, scalarToken) => { - factory.validateConfig(integrationConfig); - - return db.getUpstreamToken(scalarToken).then(upstreamToken => { - var backbone = new VectorTravisCiBackbone(roomId, upstreamToken); - return new TravisCiBot(integrationConfig, backbone); - }); -}; - -factory.validateConfig = (integrationConfig) => { - if (!integrationConfig.upstream) throw new Error("Unsupported configuration"); - if (integrationConfig.upstream.type !== "vector") throw new Error("Unsupported upstream"); - if (!UpstreamConfiguration.hasUpstream("vector")) throw new Error("Vector upstream not specified"); -}; - -module.exports = factory; \ No newline at end of file diff --git a/src/integration/impl/travisci/VectorTravisCiBackbone.js b/src/integration/impl/travisci/VectorTravisCiBackbone.js deleted file mode 100644 index 3d99d78..0000000 --- a/src/integration/impl/travisci/VectorTravisCiBackbone.js +++ /dev/null @@ -1,108 +0,0 @@ -var StubbedTravisCiBackbone = require("./StubbedTravisCiBackbone"); -var VectorScalarClient = require("../../../scalar/VectorScalarClient"); -var _ = require("lodash"); -var log = require("../../../util/LogService"); - -/** - * Backbone for Travis CI bots running on vector.im through scalar - */ -class VectorTravisCiBackbone extends StubbedTravisCiBackbone { - - /** - * Creates a new Vector Travis CI backbone - * @param {string} roomId the room ID to manage - * @param {string} upstreamScalarToken the vector scalar token - */ - constructor(roomId, upstreamScalarToken) { - super(); - this._roomId = roomId; - this._scalarToken = upstreamScalarToken; - this._info = null; - this._otherTemplates = []; - } - - /*override*/ - getUserId() { - return (this._info ? Promise.resolve() : this._getInfo()).then(() => { - return this._info.bot_user_id; - }); - } - - /*override*/ - getRepos() { - return (this._info ? Promise.resolve() : this._getInfo()).then(() => { - if (this._info.integrations.length == 0) return []; - - var rooms = _.keys(this._info.integrations[0].config.rooms); - if (rooms.indexOf(this._roomId) === -1) return []; - - var repos = _.keys(this._info.integrations[0].config.rooms[this._roomId].repos); - return _.map(repos, r => { - return {repoKey: r, template: this._info.integrations[0].config.rooms[this._roomId].repos[r].template}; - }); - }); - } - - /*override*/ - getImmutableRepos() { - return (this._info ? Promise.resolve() : this._getInfo()).then(() => { - return this._otherTemplates; - }); - } - - /*override*/ - setRepos(newRepos) { - var config = {}; - config[this._roomId] = {repos: {}}; - for (var repo of newRepos) config[this._roomId].repos[repo.repoKey] = {template: repo.template}; - - return VectorScalarClient.configureIntegration("travis-ci", this._scalarToken, { - rooms: config - }); - } - - /*override*/ - getWebhookUrl() { - // string - return (this._info ? Promise.resolve() : this._getInfo()).then(() => { - if (this._info.integrations.length == 0) return ""; - return this._info.integrations[0].config.webhook_url; - }); - } - - _getInfo() { - return VectorScalarClient.getIntegrationsForRoom(this._roomId, this._scalarToken).then(integrations => { - this._otherTemplates = []; - for (var integration of integrations) { - if (integration.self) continue; // skip - we're not looking for ones we know about - if (integration.type == "travis-ci") { - var roomIds = _.keys(integration.config.rooms); - if (roomIds.length === 0) continue; - if (roomIds.length !== 1) log.warn("VectorTravisCiBackbone", "Expected 1 room but found " + roomIds.length); - - var roomConfig = integration.config.rooms[roomIds[0]]; - var repositories = _.keys(roomConfig.repos); - - for (var repo of repositories) { - this._otherTemplates.push({ - repoKey: repo, - template: roomConfig.repos[repo].template, - ownerId: integration.user_id - }); - } - } - } - - return VectorScalarClient.getIntegration("travis-ci", this._roomId, this._scalarToken); - }).then(info => { - this._info = info; - }); - } - - /*override*/ - removeFromRoom(roomId) { - return VectorScalarClient.removeIntegration("travis-ci", roomId, this._scalarToken); - } -} - -module.exports = VectorTravisCiBackbone; \ No newline at end of file diff --git a/src/integration/index.js b/src/integration/index.js deleted file mode 100644 index dfa6a1d..0000000 --- a/src/integration/index.js +++ /dev/null @@ -1,78 +0,0 @@ -var config = require("config"); -var log = require("../util/LogService"); -var fs = require("fs"); -var path = require("path"); -var _ = require("lodash"); -var IntegrationImpl = require("./impl"); - -log.info("Integrations", "Discovering integrations"); - -var searchPath = path.join(process.cwd(), "config", "integrations"); -var files = _.filter(fs.readdirSync(searchPath), f => !fs.statSync(path.join(searchPath, f)).isDirectory() && f.endsWith(".yaml")); -var currentEnv = config.util.initParam("NODE_ENV", "development"); - -if (currentEnv !== "development" && currentEnv !== "production") - throw new Error("Unknown node environment: " + currentEnv); - -var configs = {}; - -for (var file of files) { - if (file.endsWith("_development.yaml") || file.endsWith("_production.yaml")) { - if (!file.endsWith("_" + currentEnv + ".yaml")) continue; - var fileName = file.replace("_development.yaml", "").replace("_production.yaml", "") + ".yaml"; - - if (!configs[fileName]) configs[fileName] = {}; - configs[fileName]["alt"] = config.util.parseFile(path.join(searchPath, file)) || {}; - } else { - if (!configs[file]) configs[file] = {}; - configs[file]["defaults"] = config.util.parseFile(path.join(searchPath, file)) || {}; - } -} - -var keys = _.keys(configs); -log.info("Integrations", "Discovered " + keys.length + " integrations. Parsing definitions..."); - -var linear = []; -var byUserId = {}; -var byType = {}; - -for (var key of keys) { - log.info("Integrations", "Preparing " + key); - if (!configs[key].defaults) configs[key].defaults = {}; - var merged = config.util.extendDeep(configs[key].defaults, configs[key].alt); - if (!merged['enabled']) { - log.warn("Integrations", "Integration " + key + " is not enabled - skipping"); - continue; - } - - var factory = IntegrationImpl.getFactory(merged); - if (!factory) { - log.warn("Integrations", "Integration " + key + " does not have an associated factory - skipping"); - continue; - } - try { - factory.validateConfig(merged); - } catch (err) { - log.error("Integrations", "Error while validating integration " + key + " - skipping"); - log.error("Integrations", err); - continue; - } - - linear.push(merged); - if (merged['userId']) - byUserId[merged['userId']] = merged; - - if (!byType[merged['type']]) - byType[merged['type']] = {}; - if (byType[merged['type']][merged['integrationType']]) - throw new Error("Duplicate type " + merged['type'] + " (" + merged['integrationType'] + ") at key " + key); - byType[merged['type']][merged['integrationType']] = merged; -} - -log.info("Integrations", "Loaded " + linear.length + " integrations"); - -module.exports = { - all: linear, - byUserId: byUserId, - byType: byType -}; \ No newline at end of file diff --git a/src-ts/integrations/Integration.ts b/src/integrations/Integration.ts similarity index 100% rename from src-ts/integrations/Integration.ts rename to src/integrations/Integration.ts diff --git a/src-ts/integrations/Widget.ts b/src/integrations/Widget.ts similarity index 100% rename from src-ts/integrations/Widget.ts rename to src/integrations/Widget.ts diff --git a/src/matrix/DemoBot.js b/src/matrix/DemoBot.js deleted file mode 100644 index 1b519a9..0000000 --- a/src/matrix/DemoBot.js +++ /dev/null @@ -1,66 +0,0 @@ -var sdk = require("matrix-js-sdk"); -var log = require("../util/LogService"); - -/** - * Dimension demo bot. Doesn't do anything except show how to add a self-hosted bot to Dimension - */ -class DemoBot { - - constructor(homeserverUrl, userId, accessToken) { - this._rooms = []; - - log.info("DemoBot", "Constructing bot as " + userId); - this._client = sdk.createClient({ - baseUrl: homeserverUrl, - accessToken: accessToken, - userId: userId, - }); - - this._client.on('event', event => { - if (event.getType() !== "m.room.member") return; - if (event.getStateKey() != this._client.credentials.userId) return; - if (event.getContent().membership === 'invite') { - if (this._rooms.indexOf(event.getRoomId()) !== -1) return; - log.info("DemoBot", "Joining " + event.getRoomId()); - this._client.joinRoom(event.getRoomId()).then(() => { - this._recalculateRooms(); - this._client.sendMessage(event.getRoomId(), { - msgtype: "m.notice", - body: "Hello! I'm a small bot that acts as an example for how to set up your own bot on Dimension." - }); - }); - } else this._recalculateRooms(); - }); - } - - start() { - log.info("DemoBot", "Starting bot"); - this._client.startClient(); - - this._client.on('sync', state => { - if (state == 'PREPARED') this._recalculateRooms(); - }); - } - - _recalculateRooms() { - var rooms = this._client.getRooms(); - this._rooms = []; - for (var room of rooms) { - var me = room.getMember(this._client.credentials.userId); - if (!me) continue; - - if (me.membership == "invite") { - this._client.joinRoom(room.roomId); - continue; - } - - if (me.membership != "join") continue; - this._rooms.push(room.roomId); - } - - log.verbose("DemoBot", "Currently in " + this._rooms.length + " rooms"); - } - -} - -module.exports = DemoBot; \ No newline at end of file diff --git a/src-ts/matrix/MatrixAppserviceClient.ts b/src/matrix/MatrixAppserviceClient.ts similarity index 100% rename from src-ts/matrix/MatrixAppserviceClient.ts rename to src/matrix/MatrixAppserviceClient.ts diff --git a/src/matrix/MatrixLiteClient.js b/src/matrix/MatrixLiteClient.js index 0cd9151..a774b13 100644 --- a/src/matrix/MatrixLiteClient.js +++ b/src/matrix/MatrixLiteClient.js @@ -1,83 +1,17 @@ -var request = require('request'); -var log = require("../util/LogService"); -var dns = require("dns-then"); -var Promise = require("bluebird"); -var config = require("config"); - -/** - * Represents a lightweight matrix client with minimal functionality - */ -class MatrixLiteClient { - - /** - * Creates a new matrix client - * @param {OpenID} openId the open ID to use - */ - constructor(openId) { - this._openId = openId; +"use strict"; +Object.defineProperty(exports, "__esModule", { value: true }); +var helpers_1 = require("./helpers"); +var MatrixLiteClient = /** @class */ (function () { + function MatrixLiteClient(homeserverName, accessToken) { + this.homeserverName = homeserverName; + this.accessToken = accessToken; } - - /** - * Gets the Matrix User ID that owns this open ID - * @return {Promise} resolves to the mxid - */ - getSelfMxid() { - return this._do("GET", "/_matrix/federation/v1/openid/userinfo", /*qs=*/null, /*body=*/null, /*allowSelfSigned=*/true).then((response, body) => { - var json = JSON.parse(response.body); - return json['sub']; + MatrixLiteClient.prototype.getUrlPreview = function (url) { + return helpers_1.doFederatedApiCall("GET", this.homeserverName, "/_matrix/media/r0/preview_url", { access_token: this.accessToken, url: url }).then(function (response) { + return response; }); - } - - /** - * Gets a URL preview from the media repo (as provided by the default homeserver) - * @param {string} url The URL to get the preview of - * @return {Promise<*>} resolves to the raw URL preview - */ - static getUrlPreview(url) { - return MatrixLiteClient._do(config.homeserver.name, config.homeserver.accessToken, "GET", "/_matrix/media/r0/preview_url", {url: url}).then((response, body) => { - return JSON.parse(response.body); - }); - } - - _do(method, endpoint, qs = null, body = null, allowSelfSigned = false) { - return MatrixLiteClient._do(this._openId.matrix_server_name, this._openId.access_token, method, endpoint, qs, body, allowSelfSigned); - } - - static _do(serverName, accessToken, method, endpoint, qs = null, body = null, allowSelfSigned = false) { - // HACK: We have to wrap the dns promise in a Bluebird promise just to make sure it works - var dnsPromise = dns.resolveSrv("_matrix._tcp." + serverName); - return Promise.resolve(dnsPromise).then(records => { - if (records && records.length > 0) - serverName = records[0].name + ":" + records[0].port; - }, err => { - log.warn("MatrixLiteClient", "Failed to lookup SRV for " + serverName + " - assuming none available."); - log.warn("MatrixLiteClient", err); - }).then(() => { - var url = "https://" + serverName + endpoint; - - log.verbose("MatrixLiteClient", "Performing request: " + url); - - if (!qs) qs = {}; - if (accessToken) qs['access_token'] = accessToken; - - var params = { - url: url, - method: method, - form: body, - qs: qs, - rejectUnauthorized: !allowSelfSigned - }; - - return new Promise((resolve, reject) => { - request(params, (err, response, body) => { - if (err) { - log.error("MatrixLiteClient", err); - reject(err); - } else resolve(response, body); - }); - }); - }); - } -} - -module.exports = MatrixLiteClient; \ No newline at end of file + }; + return MatrixLiteClient; +}()); +exports.MatrixLiteClient = MatrixLiteClient; +//# sourceMappingURL=MatrixLiteClient.js.map \ No newline at end of file diff --git a/src-ts/matrix/MatrixLiteClient.ts b/src/matrix/MatrixLiteClient.ts similarity index 100% rename from src-ts/matrix/MatrixLiteClient.ts rename to src/matrix/MatrixLiteClient.ts diff --git a/src-ts/matrix/MatrixOpenIdClient.ts b/src/matrix/MatrixOpenIdClient.ts similarity index 100% rename from src-ts/matrix/MatrixOpenIdClient.ts rename to src/matrix/MatrixOpenIdClient.ts diff --git a/src-ts/matrix/helpers.ts b/src/matrix/helpers.ts similarity index 100% rename from src-ts/matrix/helpers.ts rename to src/matrix/helpers.ts diff --git a/src-ts/models/MatrixEvent.ts b/src/models/MatrixEvent.ts similarity index 100% rename from src-ts/models/MatrixEvent.ts rename to src/models/MatrixEvent.ts diff --git a/src-ts/models/OpenId.ts b/src/models/OpenId.ts similarity index 100% rename from src-ts/models/OpenId.ts rename to src/models/OpenId.ts diff --git a/src-ts/models/ScalarResponses.ts b/src/models/ScalarResponses.ts similarity index 100% rename from src-ts/models/ScalarResponses.ts rename to src/models/ScalarResponses.ts diff --git a/src/scalar/ScalarClient.js b/src/scalar/ScalarClient.js index c6586b2..6ac0363 100644 --- a/src/scalar/ScalarClient.js +++ b/src/scalar/ScalarClient.js @@ -1,58 +1,36 @@ -var request = require('request'); -var log = require("../util/LogService"); -var config = require("config"); -var UpstreamConfiguration = require("../UpstreamConfiguration"); - -/** - * Represents a scalar client - */ -class ScalarClient { - - /** - * Creates a new Scalar client - */ - constructor() { +"use strict"; +Object.defineProperty(exports, "__esModule", { value: true }); +var Promise = require("bluebird"); +var request = require("request"); +var matrix_js_snippets_1 = require("matrix-js-snippets"); +var ScalarClient = /** @class */ (function () { + function ScalarClient(upstream) { + this.upstream = upstream; } - - /** - * Registers for a scalar token - * @param {OpenID} openId the open ID to register - * @returns {Promise} resolves to a scalar token - */ - register(openId) { - return this._do("POST", "/register", null, openId).then((response, body) => { - if (response.statusCode !== 200) { - log.error("ScalarClient", response.body); - return Promise.reject(response.body); - } - - return response.body['scalar_token']; - }); - } - - // TODO: Merge this, VectorScalarClient, and MatrixLiteClient into a base class - _do(method, endpoint, qs = null, body = null) { - // TODO: Generify URL - var url = UpstreamConfiguration.getUpstream("vector").url + endpoint; - - log.verbose("ScalarClient", "Performing request: " + url); - - var params = { - url: url, - method: method, - json: body, - qs: qs - }; - - return new Promise((resolve, reject) => { - request(params, (err, response, body) => { + ScalarClient.prototype.register = function (openId) { + var _this = this; + return new Promise(function (resolve, reject) { + request({ + method: "POST", + url: _this.upstream.scalarUrl + "/register", + json: openId, + }, function (err, res, _body) { if (err) { - log.error("ScalarClient", err); + matrix_js_snippets_1.LogService.error("ScalarClient", "Error registering for token"); + matrix_js_snippets_1.LogService.error("ScalarClient", err); reject(err); - } else resolve(response, body); + } + else if (res.statusCode !== 200) { + matrix_js_snippets_1.LogService.error("ScalarClient", "Got status code " + res.statusCode + " while registering for token"); + reject(new Error("Could not get token")); + } + else { + resolve(res.body); + } }); }); - } -} - -module.exports = new ScalarClient(); \ No newline at end of file + }; + return ScalarClient; +}()); +exports.ScalarClient = ScalarClient; +//# sourceMappingURL=ScalarClient.js.map \ No newline at end of file diff --git a/src-ts/scalar/ScalarClient.ts b/src/scalar/ScalarClient.ts similarity index 100% rename from src-ts/scalar/ScalarClient.ts rename to src/scalar/ScalarClient.ts diff --git a/src/scalar/VectorScalarClient.js b/src/scalar/VectorScalarClient.js deleted file mode 100644 index 5129070..0000000 --- a/src/scalar/VectorScalarClient.js +++ /dev/null @@ -1,260 +0,0 @@ -var request = require('request'); -var log = require("../util/LogService"); -var config = require("config"); -var UpstreamConfiguration = require("../UpstreamConfiguration"); - -/** - * Represents a scalar client for vector.im - */ -class VectorScalarClient { - - /** - * Creates a new vector.im Scalar client - */ - constructor() { - } - - /** - * Registers for a scalar token - * @param {OpenID} openId the open ID to register - * @returns {Promise} resolves to a scalar token - */ - register(openId) { - return this._do("POST", "/register", null, openId).then((response, body) => { - var json = JSON.parse(response.body); - return json['scalar_token']; - }); - } - - /** - * Removes a scalar integration - * @param {string} type the type of integration to remove - * @param {string} roomId the room ID to remove it from - * @param {string} scalarToken the upstream scalar token - * @return {Promise<>} resolves when complete - */ - removeIntegration(type, roomId, scalarToken) { - return this._do("POST", "/removeIntegration", {scalar_token: scalarToken}, { - type: type, - room_id: roomId - }).then((response, body) => { - if (response.statusCode !== 200) { - log.error("VectorScalarClient", response.body); - return Promise.reject(response.body); - } - - // no success processing - }); - } - - /** - * Configures an Integration on Vector - * @param {string} type the integration tpye - * @param {string} scalarToken the scalar token - * @param {*} config the config to POST to the service - * @return {Promise<>} resolves when completed - */ - configureIntegration(type, scalarToken, config) { - return this._do("POST", "/integrations/" + type + "/configureService", {scalar_token: scalarToken}, config).then((response, body) => { - if (response.statusCode !== 200) { - log.error("VectorScalarClient", response.body); - return Promise.reject(response.body); - } - - // no success processing - }); - } - - /** - * Gets all of the integrations currently in a room - * @param {string} roomId the room ID - * @param {string} scalarToken the scalar token to use - * @returns {Promise<*[]>} resolves a collection of integrations - */ - getIntegrationsForRoom(roomId, scalarToken) { - return this._do("POST", "/integrations", {scalar_token: scalarToken}, {RoomId: roomId}).then((response, body) => { - if (response.statusCode !== 200) { - log.error("VectorScalarClient", response.body); - return Promise.reject(response.body); - } - - return response.body.integrations; - }); - } - - /** - * Gets information for an integration - * @param {string} type the type to lookup - * @param {string} roomId the room ID to look in - * @param {string} scalarToken the scalar token - * @return {Promise<{bot_user_id:string,integrations:[]}>} resolves to the integration information - */ - getIntegration(type, roomId, scalarToken) { - return this._do("POST", "/integrations/" + type, {scalar_token: scalarToken}, {room_id: roomId}).then((response, body) => { - if (response.statusCode !== 200) { - log.error("VectorScalarClient", response.body); - return Promise.reject(response.body); - } - - return response.body; - }); - } - - /** - * Gets a list of supported IRC networks - * @param {string} scalarToken the scalar token - * @returns {Promise<{rid: string, title: string, domain: string, id: string}[]>} resolves to the list of IRC networks - */ - getIrcNetworks(scalarToken) { - return this._do("GET", "/bridges/irc/_matrix/provision/querynetworks", {scalar_token: scalarToken}).then((response, body) => { - if (response.statusCode !== 200) { - log.error("VectorScalarClient", response.body); - return Promise.reject(response.body); - } - - response.body = JSON.parse(response.body); - - var results = []; - for (var network of response.body["replies"]) { - var result = { - rid: network["rid"], - // Assumption: All networks have 1 server from vector - id: network["response"]["servers"][0]["network_id"], - title: network["response"]["servers"][0]["desc"], - domain: network["response"]["servers"][0]["fields"]["domain"] - }; - results.push(result); - } - - return results; - }); - } - - /** - * Gets a list of all linked IRC channels for a given room - * @param {string} roomId the room ID to look in - * @param {string} scalarToken the scalar token - * @returns {Promise<{rid: string, server: string, channel: string}>} resolves to a list of linked channels - */ - getIrcLinks(roomId, scalarToken) { - return this._do("GET", "/bridges/irc/_matrix/provision/listlinks/" + roomId, {scalar_token: scalarToken}).then((response, body) => { - if (response.statusCode !== 200) { - log.error("VectorScalarClient", response.body); - return Promise.reject(response.body); - } - - response.body = JSON.parse(response.body); - - var results = []; - for (var linkContainer of response.body["replies"]) { - for (var link of linkContainer["response"]) { - results.push({ - rid: linkContainer["rid"], - server: link["remote_room_server"], - channel: link["remote_room_channel"] - }); - } - } - - return results; - }); - } - - /** - * Gets a list of operators in a particular channel on a particular network - * @param {string} rid the network ID - * @param {string} networkServer the server that has the channel on it - * @param {string} channel the channel to look up, with prefix - * @param {string} scalarToken the scalar token - * @returns {Promise} resolves to a list of operators in the channel - */ - getIrcOperators(rid, networkServer, channel, scalarToken) { - return this._do("POST", "/bridges/irc/_matrix/provision/querylink", {scalar_token: scalarToken, rid: rid}, { - remote_room_server: networkServer, - remote_room_channel: channel - }).then((response, body) => { - if (response.statusCode !== 200) { - log.error("VectorScalarClient", response.body); - return Promise.reject(response.body); - } - - if (response.body["replies"]) { - return response.body["replies"][0]["response"]["operators"]; - } else return Promise.reject("No operators could be found"); - }); - } - - /** - * Requests an operator for permission to link an IRC channel to a matrix room - * @param {string} rid the network ID - * @param {string} roomId the matrix room ID - * @param {string} networkServer the server that has the channel on it - * @param {string} channel the channel to look up, with prefix - * @param {string} operator the channel operator's nick - * @param {string} scalarToken the scalar token - * @returns {Promise<>} resolves when completed - */ - addIrcLink(rid, roomId, networkServer, channel, operator, scalarToken) { - return this._do("POST", "/bridges/irc/_matrix/provision/link", {rid: rid, scalar_token: scalarToken}, { - matrix_room_id: roomId, - remote_room_channel: channel, - remote_room_server: networkServer, - op_nick: operator - }).then((response, body) => { - if (response.statusCode !== 200) { - log.error("VectorScalarClient", response.body); - return Promise.reject(response.body); - } - - return {status: 'ok'}; - }) - } - - /** - * Removes a channel link from a Matrix room - * @param {string} rid the network ID - * @param {string} roomId the matrix room ID - * @param {string} networkServer the server that has the channel on it - * @param {string} channel the channel to remove, with prefix - * @param {string} scalarToken the scalar token - * @returns {Promise<>} resolves when completed - */ - removeIrcLink(rid, roomId, networkServer, channel, scalarToken) { - return this._do("POST", "/bridges/irc/_matrix/provision/unlink", {rid: rid, scalar_token: scalarToken}, { - matrix_room_id: roomId, - remote_room_channel: channel, - remote_room_server: networkServer - }).then((response, body) => { - if (response.statusCode !== 200) { - log.error("VectorScalarClient", response.body); - return Promise.reject(response.body); - } - - return {status: 'ok'}; - }) - } - - _do(method, endpoint, qs = null, body = null) { - var url = UpstreamConfiguration.getUpstream("vector").url + endpoint; - - log.verbose("VectorScalarClient", "Performing request: " + url); - - var params = { - url: url, - method: method, - json: body, - qs: qs - }; - - return new Promise((resolve, reject) => { - request(params, (err, response, body) => { - if (err) { - log.error("VectorScalarClient", err); - reject(err); - } else resolve(response, body); - }); - }); - } -} - -module.exports = new VectorScalarClient(); \ No newline at end of file diff --git a/src/storage/DimensionStore.js b/src/storage/DimensionStore.js deleted file mode 100644 index 249bc55..0000000 --- a/src/storage/DimensionStore.js +++ /dev/null @@ -1,120 +0,0 @@ -var DBMigrate = require("db-migrate"); -var log = require("./../util/LogService"); -var Sequelize = require('sequelize'); -var dbConfig = require("../../config/database.json"); -var moment = require("moment"); - -/** - * Primary storage for Dimension. - */ -class DimensionStore { - - constructor() { - this._orm = null; - } - - /** - * Prepares the store for use - */ - prepare() { - var env = process.env.NODE_ENV || "development"; - log.info("DimensionStore", "Running migrations"); - return new Promise((resolve, reject)=> { - var dbMigrate = DBMigrate.getInstance(true, { - config: "./config/database.json", - env: env - }); - dbMigrate.up().then(() => { - var dbConfigEnv = dbConfig[env]; - if (!dbConfigEnv) throw new Error("Could not find DB config for " + env); - - var opts = { - host: dbConfigEnv.host || 'localhost', - dialect: 'sqlite', - pool: { - max: 5, - min: 0, - idle: 10000 - }, - storage: dbConfigEnv.filename, - logging: i => log.verbose("DimensionStore [SQL]", i) - }; - - this._orm = new Sequelize(dbConfigEnv.database || 'dimension', dbConfigEnv.username, dbConfigEnv.password, opts); - this._bindModels(); - resolve(); - }, err => { - log.error("DimensionStore", err); - reject(err); - }).catch(err => { - log.error("DimensionStore", err); - reject(err); - }); - }); - } - - _bindModels() { - // Models - this.__Tokens = this._orm.import(__dirname + "/models/tokens"); - - // Relationships - } - - /** - * Creates a new Scalar token - * @param {string} mxid the matrix user id - * @param {OpenID} openId the open ID - * @param {string} scalarToken the token associated with the user - * @param {String?} upstreamToken the upstream scalar token (optional) - * @returns {Promise<>} resolves when complete - */ - createToken(mxid, openId, scalarToken, upstreamToken) { - return this.__Tokens.create({ - matrixUserId: mxid, - matrixServerName: openId.matrix_server_name, - matrixAccessToken: openId.access_token, - scalarToken: scalarToken, - upstreamToken: upstreamToken, - expires: moment().add(openId.expires_in, 'seconds').toDate() - }); - } - - /** - * Checks to determine if a token is valid or not - * @param {string} scalarToken the scalar token to check - * @returns {Promise<>} resolves if valid, rejected otherwise - */ - checkToken(scalarToken) { - return this.__Tokens.find({where: {scalarToken: scalarToken}}).then(token => { - if (!token) return Promise.reject(new Error("Token not found")); - //if (moment().isAfter(moment(token.expires))) return this.__Tokens.destroy({where: {id: token.id}}).then(() => Promise.reject()); - return Promise.resolve(); - }); - } - - /** - * Gets the user ID that owns a given token, returning a falsey value if no one owns the token. - * @param {string} scalarToken the scalar token to check - * @returns {Promise} resolves to the user ID, or a falsey value if no user ID was found - */ - getTokenOwner(scalarToken) { - return this.__Tokens.find({where:{scalarToken: scalarToken}}).then(token => { - if (!token) return Promise.reject(new Error("Token not found")); - return Promise.resolve(token.matrixUserId); - }); - } - - /** - * Gets the upstream token for a given scalar token - * @param {string} scalarToken the scalar token to lookup - * @returns {Promise} resolves to the upstream token, or null if not found - */ - getUpstreamToken(scalarToken) { - return this.__Tokens.find({where: {scalarToken: scalarToken}}).then(token => { - if (!token) return null; - return token.upstreamToken; - }); - } -} - -module.exports = DimensionStore; \ No newline at end of file diff --git a/src/storage/models/tokens.js b/src/storage/models/tokens.js deleted file mode 100644 index 75c9167..0000000 --- a/src/storage/models/tokens.js +++ /dev/null @@ -1,45 +0,0 @@ -module.exports = function (sequelize, DataTypes) { - return sequelize.define('tokens', { - id: { - type: DataTypes.INTEGER, - allowNull: false, - autoIncrement: true, - primaryKey: true, - field: 'id' - }, - matrixUserId: { - type: DataTypes.STRING, - allowNull: false, - field: 'matrixUserId' - }, - matrixServerName: { - type: DataTypes.STRING, - allowNull: false, - field: 'matrixServerName' - }, - matrixAccessToken: { - type: DataTypes.STRING, - allowNull: false, - field: 'matrixAccessToken' - }, - scalarToken: { - type: DataTypes.STRING, - allowNull: false, - field: 'scalarToken' - }, - upstreamToken: { - type: DataTypes.STRING, - allowNull: true, - field: 'upstreamToken' - }, - expires: { - type: DataTypes.TIME, - allowNull: false, - field: 'expires' - } - }, { - tableName: 'tokens', - underscored: false, - timestamps: false - }); -}; diff --git a/src-ts/temp_todo.txt b/src/temp_todo.txt similarity index 100% rename from src-ts/temp_todo.txt rename to src/temp_todo.txt diff --git a/src/util/LogService.js b/src/util/LogService.js deleted file mode 100644 index e6c040f..0000000 --- a/src/util/LogService.js +++ /dev/null @@ -1,100 +0,0 @@ -var winston = require("winston"); -var chalk = require("chalk"); -var config = require("config"); -var fs = require('fs'); -var moment = require('moment'); - -try { - fs.mkdirSync('logs') -} catch (err) { - if (err.code !== 'EEXIST') throw err -} - -const TERM_COLORS = { - error: "red", - warn: "yellow", - info: "blue", - verbose: "white", - silly: "grey", -}; - -function winstonColorFormatter(options) { - options.level = chalk[TERM_COLORS[options.level]](options.level); - return winstonFormatter(options); -} - -function winstonFormatter(options) { - return options.timestamp() + ' ' + options.level + ' ' + (options.message ? options.message : '') + - (options.meta && Object.keys(options.meta).length ? '\n\t' + JSON.stringify(options.meta) : '' ); -} - -function getTimestamp() { - return moment().format('MMM-D-YYYY HH:mm:ss.SSS Z'); -} - -var loggingConfig = config.get('logging'); - -var transports = []; -transports.push(new (winston.transports.File)({ - json: false, - name: "file", - filename: loggingConfig.file, - timestamp: getTimestamp, - formatter: winstonFormatter, - level: loggingConfig.fileLevel, - maxsize: loggingConfig.rotate.size, - maxFiles: loggingConfig.rotate.count, - zippedArchive: false -})); - -if (loggingConfig.console) { - transports.push(new (winston.transports.Console)({ - json: false, - name: "console", - timestamp: getTimestamp, - formatter: winstonColorFormatter, - level: loggingConfig.consoleLevel - })); -} - -var log = new winston.Logger({ - transports: transports, - levels: { - error: 0, - warn: 1, - info: 2, - verbose: 3, - silly: 4 - } -}); - -function doLog(level, module, messageOrObject) { - if (typeof(messageOrObject) === 'object' && !(messageOrObject instanceof Error)) - messageOrObject = JSON.stringify(messageOrObject); - var message = "[" + module + "] " + messageOrObject; - log.log(level, message); -} - -class LogService { - static info(module, message) { - doLog('info', module, message); - } - - static warn(module, message) { - doLog('warn', module, message); - } - - static error(module, message) { - doLog('error', module, message); - } - - static verbose(module, message) { - doLog('verbose', module, message); - } - - static silly(module, message) { - doLog('silly', module, message); - } -} - -module.exports = LogService; \ No newline at end of file diff --git a/src-ts/version.ts b/src/version.ts similarity index 100% rename from src-ts/version.ts rename to src/version.ts diff --git a/tsconfig-app.json b/tsconfig-app.json index e58ba89..15a18f1 100644 --- a/tsconfig-app.json +++ b/tsconfig-app.json @@ -13,6 +13,6 @@ ] }, "include": [ - "./src-ts/**/*" + "./src/**/*" ] } \ No newline at end of file