Skip to content
This repository has been archived by the owner on Aug 10, 2023. It is now read-only.

Commit

Permalink
Merge branch 'travis/msc2140-tos'
Browse files Browse the repository at this point in the history
  • Loading branch information
turt2live committed Jul 23, 2019
2 parents 4e220bb + e006851 commit dd53cb8
Show file tree
Hide file tree
Showing 111 changed files with 2,855 additions and 625 deletions.
30 changes: 21 additions & 9 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 3 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -63,14 +63,15 @@
"@angular/compiler": "^8.0.3",
"@angular/core": "^8.0.3",
"@angular/forms": "^8.0.3",
"@angular/http": "^7.2.15",
"@angular/platform-browser": "^8.0.3",
"@angular/platform-browser-dynamic": "^8.0.3",
"@angular/router": "^8.0.3",
"@angularclass/hmr": "^2.1.3",
"@angularclass/hmr-loader": "^3.0.4",
"@babel/core": "^7.4.5",
"@babel/preset-env": "^7.4.5",
"@ckeditor/ckeditor5-angular": "^1.1.0",
"@ckeditor/ckeditor5-build-classic": "^12.2.0",
"@fortawesome/fontawesome": "^1.1.8",
"@fortawesome/fontawesome-free-brands": "^5.0.13",
"@fortawesome/fontawesome-free-regular": "^5.0.13",
Expand All @@ -93,6 +94,7 @@
"goby": "^1.1.2",
"html-loader": "^0.5.5",
"html-webpack-plugin": "^3.2.0",
"iso-639-1": "^2.0.5",
"jquery": "^3.4.1",
"json-loader": "^0.5.7",
"mini-css-extract-plugin": "^0.7.0",
Expand Down
3 changes: 2 additions & 1 deletion src/MemoryCache.ts
Original file line number Diff line number Diff line change
Expand Up @@ -54,4 +54,5 @@ export const CACHE_TELEGRAM_BRIDGE = "telegram-bridge";
export const CACHE_WEBHOOKS_BRIDGE = "webhooks-bridge";
export const CACHE_GITTER_BRIDGE = "gitter-bridge";
export const CACHE_SIMPLE_BOTS = "simple-bots";
export const CACHE_SLACK_BRIDGE = "slack-bridge";
export const CACHE_SLACK_BRIDGE = "slack-bridge";
export const CACHE_TERMS = "terms";
7 changes: 5 additions & 2 deletions src/api/ApiError.ts
Original file line number Diff line number Diff line change
Expand Up @@ -26,16 +26,19 @@ export class ApiError {
* then converted to JSON as {message: "your_message"})
* @param {string} errCode The internal error code to describe what went wrong
*/
constructor(statusCode: number, json: string | object, errCode = "D_UNKNOWN") {
constructor(statusCode: number, json: string | object, errCode = "M_UNKNOWN") {
// Because typescript is just plain dumb
// https://stackoverflow.com/questions/31626231/custom-error-class-in-typescript
Error.apply(this, ["ApiError"]);

if (typeof(json) === "string") json = {message: json};
if (typeof (json) === "string") json = {message: json};
this.jsonResponse = json;
this.statusCode = statusCode;
this.errorCode = errCode;

this.jsonResponse["dim_errcode"] = this.errorCode;

if (!this.jsonResponse['error']) this.jsonResponse['error'] = this.jsonResponse['message'];
if (!this.jsonResponse['errcode']) this.jsonResponse['errcode'] = errCode;
}
}
13 changes: 9 additions & 4 deletions src/api/Webserver.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import { Server } from "typescript-rest";
import * as _ from "lodash";
import config from "../config";
import { ApiError } from "./ApiError";
import MSCSecurity from "./security/MSCSecurity";
import MatrixSecurity from "./security/MatrixSecurity";

/**
* Web server for Dimension. Handles the API routes for the admin, scalar, dimension, and matrix APIs.
Expand All @@ -26,10 +26,10 @@ export default class Webserver {
private loadRoutes() {
// TODO: Rename services to controllers, and controllers to services. They're backwards.

const apis = ["scalar", "dimension", "admin", "matrix", "msc"].map(a => path.join(__dirname, a, "*.js"));
const apis = ["scalar", "dimension", "admin", "matrix"].map(a => path.join(__dirname, a, "*.js"));
const router = express.Router();
Server.useIoC();
Server.registerAuthenticator(new MSCSecurity());
Server.registerAuthenticator(new MatrixSecurity());
apis.forEach(a => Server.loadServices(router, [a]));
const routes = _.uniq(router.stack.map(r => r.route.path));
for (const route of routes) {
Expand Down Expand Up @@ -71,8 +71,13 @@ export default class Webserver {
next();
});
this.app.use((_req, res, next) => {
if (res.headersSent) {
next();
return;
}

res.setHeader("Access-Control-Allow-Origin", "*");
res.setHeader("Access-Control-Allow-Headers", "Origin, X-Requested-With, Content-Type, Accept");
res.setHeader("Access-Control-Allow-Headers", "Origin, X-Requested-With, Content-Type, Accept, Authorization");
next();
});
}
Expand Down
26 changes: 14 additions & 12 deletions src/api/admin/AdminAppserviceService.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
import { GET, Path, PathParam, POST, QueryParam } from "typescript-rest";
import { AdminService } from "./AdminService";
import { Context, GET, Path, PathParam, POST, Security, ServiceContext } from "typescript-rest";
import AppService from "../../db/models/AppService";
import { AppserviceStore } from "../../db/AppserviceStore";
import { ApiError } from "../ApiError";
import { MatrixAppserviceClient } from "../../matrix/MatrixAppserviceClient";
import { LogService } from "matrix-js-snippets";
import { ROLE_ADMIN, ROLE_USER } from "../security/MatrixSecurity";

interface AppserviceResponse {
id: string;
Expand All @@ -23,18 +23,20 @@ interface AppserviceCreateRequest {
@Path("/api/v1/dimension/admin/appservices")
export class AdminAppserviceService {

@Context
private context: ServiceContext;

@GET
@Path("all")
public async getAppservices(@QueryParam("scalar_token") scalarToken: string): Promise<AppserviceResponse[]> {
await AdminService.validateAndGetAdminTokenOwner(scalarToken);
@Security([ROLE_USER, ROLE_ADMIN])
public async getAppservices(): Promise<AppserviceResponse[]> {
return (await AppService.findAll()).map(a => this.mapAppservice(a));
}

@GET
@Path(":appserviceId")
public async getAppservice(@QueryParam("scalar_token") scalarToken: string, @PathParam("appserviceId") asId: string): Promise<AppserviceResponse> {
await AdminService.validateAndGetAdminTokenOwner(scalarToken);

@Security([ROLE_USER, ROLE_ADMIN])
public async getAppservice(@PathParam("appserviceId") asId: string): Promise<AppserviceResponse> {
try {
const appservice = await AppserviceStore.getAppservice(asId);
return this.mapAppservice(appservice);
Expand All @@ -46,8 +48,9 @@ export class AdminAppserviceService {

@POST
@Path("new")
public async createAppservice(@QueryParam("scalar_token") scalarToken: string, request: AppserviceCreateRequest): Promise<AppserviceResponse> {
const userId = await AdminService.validateAndGetAdminTokenOwner(scalarToken);
@Security([ROLE_USER, ROLE_ADMIN])
public async createAppservice(request: AppserviceCreateRequest): Promise<AppserviceResponse> {
const userId = this.context.request.user.userId;

// Trim off the @ sign if it's on the prefix
if (request.userPrefix[0] === "@") {
Expand All @@ -66,9 +69,8 @@ export class AdminAppserviceService {

@POST
@Path(":appserviceId/test")
public async test(@QueryParam("scalar_token") scalarToken: string, @PathParam("appserviceId") asId: string): Promise<any> {
await AdminService.validateAndGetAdminTokenOwner(scalarToken);

@Security([ROLE_USER, ROLE_ADMIN])
public async test(@PathParam("appserviceId") asId: string): Promise<any> {
const appservice = await AppserviceStore.getAppservice(asId);
const client = new MatrixAppserviceClient(appservice);
const userId = await client.whoAmI();
Expand Down
39 changes: 20 additions & 19 deletions src/api/admin/AdminCustomSimpleBotService.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
import { DELETE, GET, Path, PathParam, POST, QueryParam } from "typescript-rest";
import { AdminService } from "./AdminService";
import { Context, DELETE, GET, Path, PathParam, POST, Security, ServiceContext } from "typescript-rest";
import { ApiError } from "../ApiError";
import { LogService } from "matrix-js-snippets";
import { BotStore } from "../../db/BotStore";
import { Cache, CACHE_INTEGRATIONS } from "../../MemoryCache";
import { ROLE_ADMIN, ROLE_USER } from "../security/MatrixSecurity";

interface BotResponse extends BotRequest {
id: number;
Expand Down Expand Up @@ -31,28 +31,30 @@ interface BotProfile {
@Path("/api/v1/dimension/admin/bots/simple/custom")
export class AdminCustomSimpleBotService {

@Context
private context: ServiceContext;

@GET
@Path("all")
public async getBots(@QueryParam("scalar_token") scalarToken: string): Promise<BotResponse[]> {
await AdminService.validateAndGetAdminTokenOwner(scalarToken);
@Security([ROLE_USER, ROLE_ADMIN])
public async getBots(): Promise<BotResponse[]> {
return BotStore.getCustomBots();
}

@GET
@Path(":botId")
public async getBot(@QueryParam("scalar_token") scalarToken: string, @PathParam("botId") botId: number): Promise<BotResponse> {
await AdminService.validateAndGetAdminTokenOwner(scalarToken);

@Security([ROLE_USER, ROLE_ADMIN])
public async getBot(@PathParam("botId") botId: number): Promise<BotResponse> {
const bot = await BotStore.getCustomBot(botId);
if (!bot) throw new ApiError(404, "Bot not found");
return bot;
}

@POST
@Path("new")
public async createBot(@QueryParam("scalar_token") scalarToken: string, request: BotRequest): Promise<BotResponse> {
const userId = await AdminService.validateAndGetAdminTokenOwner(scalarToken);

@Security([ROLE_USER, ROLE_ADMIN])
public async createBot(request: BotRequest): Promise<BotResponse> {
const userId = this.context.request.user.userId;
const bot = await BotStore.createCustom(request);
LogService.info("AdminCustomSimpleBotService", userId + " created a simple bot");
Cache.for(CACHE_INTEGRATIONS).clear();
Expand All @@ -61,9 +63,9 @@ export class AdminCustomSimpleBotService {

@POST
@Path(":botId")
public async updateBot(@QueryParam("scalar_token") scalarToken: string, @PathParam("botId") botId: number, request: BotRequest): Promise<BotResponse> {
const userId = await AdminService.validateAndGetAdminTokenOwner(scalarToken);

@Security([ROLE_USER, ROLE_ADMIN])
public async updateBot(@PathParam("botId") botId: number, request: BotRequest): Promise<BotResponse> {
const userId = this.context.request.user.userId;
const bot = await BotStore.updateCustom(botId, request);
LogService.info("AdminCustomSimpleBotService", userId + " updated a simple bot");
Cache.for(CACHE_INTEGRATIONS).clear();
Expand All @@ -72,9 +74,9 @@ export class AdminCustomSimpleBotService {

@DELETE
@Path(":botId")
public async deleteBot(@QueryParam("scalar_token") scalarToken: string, @PathParam("botId") botId: number): Promise<any> {
const userId = await AdminService.validateAndGetAdminTokenOwner(scalarToken);

@Security([ROLE_USER, ROLE_ADMIN])
public async deleteBot(@PathParam("botId") botId: number): Promise<any> {
const userId = this.context.request.user.userId;
await BotStore.deleteCustom(botId);
LogService.info("AdminCustomSimpleBotService", userId + " deleted a simple bot");
Cache.for(CACHE_INTEGRATIONS).clear();
Expand All @@ -83,9 +85,8 @@ export class AdminCustomSimpleBotService {

@GET
@Path("profile/:userId")
public async getProfile(@QueryParam("scalar_token") scalarToken: string, @PathParam("userId") userId: string): Promise<BotProfile> {
await AdminService.validateAndGetAdminTokenOwner(scalarToken);

@Security([ROLE_USER, ROLE_ADMIN])
public async getProfile(@PathParam("userId") userId: string): Promise<BotProfile> {
const profile = await BotStore.getProfile(userId);
return {name: profile.displayName, avatarUrl: profile.avatarMxc};
}
Expand Down
41 changes: 21 additions & 20 deletions src/api/admin/AdminGitterService.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
import { GET, Path, PathParam, POST, QueryParam } from "typescript-rest";
import { AdminService } from "./AdminService";
import { Context, GET, Path, PathParam, POST, Security, ServiceContext } from "typescript-rest";
import { Cache, CACHE_GITTER_BRIDGE, CACHE_INTEGRATIONS } from "../../MemoryCache";
import { LogService } from "matrix-js-snippets";
import { ApiError } from "../ApiError";
import GitterBridgeRecord from "../../db/models/GitterBridgeRecord";
import Upstream from "../../db/models/Upstream";
import { ROLE_ADMIN, ROLE_USER } from "../security/MatrixSecurity";

interface CreateWithUpstream {
upstreamId: number;
Expand All @@ -27,11 +27,13 @@ interface BridgeResponse {
@Path("/api/v1/dimension/admin/gitter")
export class AdminGitterService {

@Context
private context: ServiceContext;

@GET
@Path("all")
public async getBridges(@QueryParam("scalar_token") scalarToken: string): Promise<BridgeResponse[]> {
await AdminService.validateAndGetAdminTokenOwner(scalarToken);

@Security([ROLE_USER, ROLE_ADMIN])
public async getBridges(): Promise<BridgeResponse[]> {
const bridges = await GitterBridgeRecord.findAll();
return Promise.all(bridges.map(async b => {
return {
Expand All @@ -45,9 +47,8 @@ export class AdminGitterService {

@GET
@Path(":bridgeId")
public async getBridge(@QueryParam("scalar_token") scalarToken: string, @PathParam("bridgeId") bridgeId: number): Promise<BridgeResponse> {
await AdminService.validateAndGetAdminTokenOwner(scalarToken);

@Security([ROLE_USER, ROLE_ADMIN])
public async getBridge(@PathParam("bridgeId") bridgeId: number): Promise<BridgeResponse> {
const telegramBridge = await GitterBridgeRecord.findByPk(bridgeId);
if (!telegramBridge) throw new ApiError(404, "Gitter Bridge not found");

Expand All @@ -61,9 +62,9 @@ export class AdminGitterService {

@POST
@Path(":bridgeId")
public async updateBridge(@QueryParam("scalar_token") scalarToken: string, @PathParam("bridgeId") bridgeId: number, request: CreateSelfhosted): Promise<BridgeResponse> {
const userId = await AdminService.validateAndGetAdminTokenOwner(scalarToken);

@Security([ROLE_USER, ROLE_ADMIN])
public async updateBridge(@PathParam("bridgeId") bridgeId: number, request: CreateSelfhosted): Promise<BridgeResponse> {
const userId = this.context.request.user.userId;
const bridge = await GitterBridgeRecord.findByPk(bridgeId);
if (!bridge) throw new ApiError(404, "Bridge not found");

Expand All @@ -74,14 +75,14 @@ export class AdminGitterService {

Cache.for(CACHE_GITTER_BRIDGE).clear();
Cache.for(CACHE_INTEGRATIONS).clear();
return this.getBridge(scalarToken, bridge.id);
return this.getBridge(bridge.id);
}

@POST
@Path("new/upstream")
public async newConfigForUpstream(@QueryParam("scalar_token") scalarToken: string, request: CreateWithUpstream): Promise<BridgeResponse> {
const userId = await AdminService.validateAndGetAdminTokenOwner(scalarToken);

@Security([ROLE_USER, ROLE_ADMIN])
public async newConfigForUpstream(request: CreateWithUpstream): Promise<BridgeResponse> {
const userId = this.context.request.user.userId;
const upstream = await Upstream.findByPk(request.upstreamId);
if (!upstream) throw new ApiError(400, "Upstream not found");

Expand All @@ -93,14 +94,14 @@ export class AdminGitterService {

Cache.for(CACHE_GITTER_BRIDGE).clear();
Cache.for(CACHE_INTEGRATIONS).clear();
return this.getBridge(scalarToken, bridge.id);
return this.getBridge(bridge.id);
}

@POST
@Path("new/selfhosted")
public async newSelfhosted(@QueryParam("scalar_token") scalarToken: string, request: CreateSelfhosted): Promise<BridgeResponse> {
const userId = await AdminService.validateAndGetAdminTokenOwner(scalarToken);

@Security([ROLE_USER, ROLE_ADMIN])
public async newSelfhosted(request: CreateSelfhosted): Promise<BridgeResponse> {
const userId = this.context.request.user.userId;
const bridge = await GitterBridgeRecord.create({
provisionUrl: request.provisionUrl,
isEnabled: true,
Expand All @@ -109,6 +110,6 @@ export class AdminGitterService {

Cache.for(CACHE_GITTER_BRIDGE).clear();
Cache.for(CACHE_INTEGRATIONS).clear();
return this.getBridge(scalarToken, bridge.id);
return this.getBridge(bridge.id);
}
}

0 comments on commit dd53cb8

Please sign in to comment.