diff --git a/mx-tester.yml b/mx-tester.yml index 79feba98..ba0af398 100644 --- a/mx-tester.yml +++ b/mx-tester.yml @@ -5,8 +5,6 @@ up: - docker run --rm --network $MX_TEST_NETWORK_NAME --name mjolnir-test-postgres --domainname mjolnir-test-postgres -e POSTGRES_PASSWORD=mjolnir-test -e POSTGRES_USER=mjolnir-tester -e POSTGRES_DB=mjolnir-test-db -d -p 127.0.0.1:8083:5432 postgres # Wait until postgresql is ready - until psql postgres://mjolnir-tester:mjolnir-test@localhost:8083/mjolnir-test-db -c ""; do echo "Waiting for psql..."; sleep 1s; done - # Make table in postgres - - psql postgres://mjolnir-tester:mjolnir-test@localhost:8083/mjolnir-test-db -c "CREATE TABLE mjolnir (local_part VARCHAR(255), owner VARCHAR(255), management_room TEXT)" # Launch the reverse proxy, listening for connections *only* on the local host. - docker run --rm --network host --name mjolnir-test-reverse-proxy -p 127.0.0.1:8081:80 -v $MX_TEST_CWD/test/nginx.conf:/etc/nginx/nginx.conf:ro -d nginx - yarn install diff --git a/package.json b/package.json index f1b6547d..0a82b5b2 100644 --- a/package.json +++ b/package.json @@ -57,7 +57,7 @@ "humanize-duration-ts": "^2.1.1", "js-yaml": "^4.1.0", "jsdom": "^16.6.0", - "matrix-appservice-bridge": "8.0.0", + "matrix-appservice-bridge": "8.1.1", "parse-duration": "^1.0.2", "pg": "^8.8.0", "shell-quote": "^1.7.3", diff --git a/src/appservice/AppService.ts b/src/appservice/AppService.ts index 30b6d39b..97351fa8 100644 --- a/src/appservice/AppService.ts +++ b/src/appservice/AppService.ts @@ -27,7 +27,8 @@ limitations under the License. import { AppServiceRegistration, Bridge, Request, WeakEvent, BridgeContext, MatrixUser, Logger } from "matrix-appservice-bridge"; import { MjolnirManager } from ".//MjolnirManager"; -import { DataStore, PgDataStore } from ".//datastore"; +import { DataStore } from ".//datastore"; +import { PgDataStore } from "./postgres/PgDataStore"; import { Api } from "./Api"; import { IConfig } from "./config/config"; import { AccessControl } from "./AccessControl"; diff --git a/src/appservice/datastore.ts b/src/appservice/datastore.ts index a12511a8..2a29b87d 100644 --- a/src/appservice/datastore.ts +++ b/src/appservice/datastore.ts @@ -24,7 +24,6 @@ limitations under the License. * However, this file is modified and the modifications in this file * are NOT distributed, contributed, committed, or licensed under the Apache License. */ -import { Client } from "pg"; export interface MjolnirRecord { local_part: string, @@ -67,53 +66,4 @@ export interface DataStore { lookupByLocalPart(localPart: string): Promise; } -export class PgDataStore implements DataStore { - private pgClient: Client; - constructor(connectionString: string) { - this.pgClient = new Client({ connectionString: connectionString }); - } - - public async init(): Promise { - await this.pgClient.connect(); - } - - public async close(): Promise { - await this.pgClient.end() - } - - public async list(): Promise { - const result = await this.pgClient.query("SELECT local_part, owner, management_room FROM mjolnir"); - - if (!result.rowCount) { - return []; - } - - return result.rows; - } - - public async store(mjolnirRecord: MjolnirRecord): Promise { - await this.pgClient.query( - "INSERT INTO mjolnir (local_part, owner, management_room) VALUES ($1, $2, $3)", - [mjolnirRecord.local_part, mjolnirRecord.owner, mjolnirRecord.management_room], - ); - } - - public async lookupByOwner(owner: string): Promise { - const result = await this.pgClient.query( - "SELECT local_part, owner, management_room FROM mjolnir WHERE owner = $1", - [owner], - ); - - return result.rows; - } - - public async lookupByLocalPart(localPart: string): Promise { - const result = await this.pgClient.query( - "SELECT local_part, owner, management_room FROM mjolnir WHERE local_part = $1", - [localPart], - ); - - return result.rows; - } -} diff --git a/src/appservice/postgres/PgDataStore.ts b/src/appservice/postgres/PgDataStore.ts new file mode 100644 index 00000000..3360be1d --- /dev/null +++ b/src/appservice/postgres/PgDataStore.ts @@ -0,0 +1,68 @@ +/* +Copyright 2022 The Matrix.org Foundation C.I.C. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +import { PostgresStore, SchemaUpdateFunction } from "matrix-appservice-bridge"; +import { DataStore, MjolnirRecord } from "../datastore"; + +function getSchema(): SchemaUpdateFunction[] { + const nSchema = 1; + const schema = []; + for (let schemaID = 1; schemaID < nSchema + 1; schemaID++) { + schema.push(require(`./schema/v${schemaID}`).runSchema); + } + return schema; +} + +export class PgDataStore extends PostgresStore implements DataStore { + + constructor(connectionString: string) { + super(getSchema(), { url: connectionString }) + } + + public async init(): Promise { + await this.ensureSchema(); + } + + public async close(): Promise { + await this.destroy(); + } + + public async list(): Promise { + const result = await this.sql`SELECT local_part, owner, management_room FROM mjolnir`; + if (!result.count) { + return []; + } + + return result.flat() as MjolnirRecord[]; + } + + public async store(mjolnirRecord: MjolnirRecord): Promise { + await this.sql`INSERT INTO mjolnir (local_part, owner, management_room) + VALUES (${mjolnirRecord.local_part}, ${mjolnirRecord.owner}, ${mjolnirRecord.management_room})`; + } + + public async lookupByOwner(owner: string): Promise { + const result = await this.sql`SELECT local_part, owner, management_room FROM mjolnir + WHERE owner = ${owner}`; + return result.flat() as MjolnirRecord[]; + } + + public async lookupByLocalPart(localPart: string): Promise { + const result = await this.sql`SELECT local_part, owner, management_room FROM mjolnir + WHERE local_part = ${localPart}`; + return result.flat() as MjolnirRecord[]; + } +} diff --git a/src/appservice/postgres/schema/v1.ts b/src/appservice/postgres/schema/v1.ts new file mode 100644 index 00000000..4972208b --- /dev/null +++ b/src/appservice/postgres/schema/v1.ts @@ -0,0 +1,8 @@ + +import postgres from 'postgres'; + +export async function runSchema(sql: postgres.Sql) { + await sql.begin(s => [ + s`CREATE TABLE mjolnir (local_part VARCHAR(255), owner VARCHAR(255), management_room TEXT);` + ]); +} diff --git a/yarn.lock b/yarn.lock index a3dfc362..f263da60 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1265,10 +1265,10 @@ expect@^27.0.6: jest-message-util "^27.2.4" jest-regex-util "^27.0.6" -express-rate-limit@^6.2.0: - version "6.5.1" - resolved "https://registry.yarnpkg.com/express-rate-limit/-/express-rate-limit-6.5.1.tgz#2b4c329f03265f94f19613519b169afbd018e783" - integrity sha512-pxO6ioBLd3i8IHL+RmJtL4noYzte5fugoMdaDabtU4hcg53+x0QkTwfPtM7vWD0YUaXQgNj9NRdzmps+CHEHlA== +express-rate-limit@^6.7.0: + version "6.7.0" + resolved "https://registry.yarnpkg.com/express-rate-limit/-/express-rate-limit-6.7.0.tgz#6aa8a1bd63dfe79702267b3af1161a93afc1d3c2" + integrity sha512-vhwIdRoqcYB/72TK3tRZI+0ttS8Ytrk24GfmsxDXK9o9IhHNO5bXRiXQSExPQ4GbaE5tvIS7j1SGrxsuWs+sGA== express@^4.17: version "4.17.3" @@ -2235,17 +2235,17 @@ make-error@^1.1.1: resolved "https://registry.yarnpkg.com/make-error/-/make-error-1.3.6.tgz#2eb2e37ea9b67c4891f684a1394799af484cf7a2" integrity sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw== -matrix-appservice-bridge@8.0.0: - version "8.0.0" - resolved "https://registry.yarnpkg.com/matrix-appservice-bridge/-/matrix-appservice-bridge-8.0.0.tgz#6849ac05c281399b2c2b35daba784f8291d3b35d" - integrity sha512-XFo3avVfKb34d7kalXcsi0vThlnqmrwvewcfhjintmpbFlwu54/lvdbykFSyu2kT8BY1zUtDz7iQ3Q3RAyaN1g== +matrix-appservice-bridge@8.1.1: + version "8.1.1" + resolved "https://registry.yarnpkg.com/matrix-appservice-bridge/-/matrix-appservice-bridge-8.1.1.tgz#9bf37d39742aed276e01d01e5c28c75d7ba1fcf7" + integrity sha512-6QYvTxe8kLXa2u+npeFUJph0PVqaOK6BPyC2J4bM0iklS8wNyprwzpToxGUr0WZS6D8vRc8qbyxhN1JTUbu9kw== dependencies: "@alloc/quick-lru" "^5.2.0" "@types/pkginfo" "^0.4.0" axios "^0.27.2" chalk "^4.1.0" express "^4.18.1" - express-rate-limit "^6.2.0" + express-rate-limit "^6.7.0" extend "^3.0.2" ip-cidr "^3.0.4" is-my-json-valid "^2.20.5"