Skip to content

Commit 09d7ce2

Browse files
committed
Add MediaProxy support to serve authenticated Matrix media
1 parent af9075b commit 09d7ce2

File tree

8 files changed

+105
-19
lines changed

8 files changed

+105
-19
lines changed

config/config.sample.yaml

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,17 @@ db:
5555
#key_file: /path/to/tls.key
5656
#crt_file: /path/to/tls.crt
5757

58+
mediaProxy:
59+
# To generate a .jwk file:
60+
# $ node src/generate-signing-key.js > signingkey.jwk
61+
signingKeyPath: "signingkey.jwk"
62+
# How long should the generated URLs be valid for
63+
ttlSeconds: 3600
64+
# The port for the media proxy to listen on
65+
bindPort: 11111
66+
# The publically accessible URL to the media proxy
67+
publicUrl: "https://slack.bridge/media"
68+
5869
# Real Time Messaging API (RTM)
5970
# Optional if slack_hook_port and inbound_uri_prefix are defined, required otherwise.
6071
#

config/slack-config-schema.yaml

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,18 @@ properties:
3434
type: number
3535
inactive_after_days:
3636
type: number
37+
mediaProxy:
38+
type: "object"
39+
properties:
40+
signingKeyPath:
41+
type: "string"
42+
ttlSeconds:
43+
type: "integer"
44+
bindPort:
45+
type: "integer"
46+
publicUrl:
47+
type: "string"
48+
required: ["signingKeyPath", "ttlSeconds", "bindPort", "publicUrl"]
3749
rtm:
3850
type: object
3951
required: ["enable"]

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,7 @@
4444
"classnames": "^2.5.1",
4545
"escape-string-regexp": "^4.0.0",
4646
"https-proxy-agent": "^7.0.4",
47-
"matrix-appservice-bridge": "^10.1.0",
47+
"matrix-appservice-bridge": "^10.3.1",
4848
"matrix-bot-sdk": "^0.7.1",
4949
"matrix-widget-api": "^1.6.0",
5050
"minimist": "^1.2.8",

src/IConfig.ts

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -109,4 +109,11 @@ export interface IConfig {
109109
onboard_users?: boolean;
110110
direct_messages?: AllowDenyConfig;
111111
}
112+
113+
mediaProxy: {
114+
signingKeyPath: string;
115+
ttlSeconds: number;
116+
bindPort: number;
117+
publicUrl: string;
118+
}
112119
}

src/Main.ts

Lines changed: 31 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -15,13 +15,16 @@ limitations under the License.
1515
*/
1616

1717
import {
18-
Bridge, BridgeBlocker, PrometheusMetrics, StateLookup,
18+
Bridge, BridgeBlocker, PrometheusMetrics, StateLookup, MediaProxy,
1919
Logger, Intent, UserMembership, WeakEvent, PresenceEvent,
2020
AppService, AppServiceRegistration, UserActivityState, UserActivityTracker,
21-
UserActivityTrackerConfig, MembershipQueue, PowerLevelContent, StateLookupEvent } from "matrix-appservice-bridge";
21+
UserActivityTrackerConfig, MembershipQueue, PowerLevelContent, StateLookupEvent,
22+
} from "matrix-appservice-bridge";
2223
import { Gauge, Counter } from "prom-client";
2324
import * as path from "path";
25+
import * as fs from "fs";
2426
import * as randomstring from "randomstring";
27+
import { webcrypto } from "node:crypto";
2528
import { WebClient } from "@slack/web-api";
2629
import { IConfig, CACHING_DEFAULTS } from "./IConfig";
2730
import { OAuth2 } from "./OAuth2";
@@ -148,6 +151,8 @@ export class Main {
148151
public slackRtm?: SlackRTMHandler;
149152
private slackHookHandler?: SlackHookHandler;
150153

154+
public mediaProxy?: MediaProxy;
155+
151156
private provisioner: Provisioner;
152157

153158
private bridgeBlocker?: BridgeBlocker;
@@ -333,6 +338,22 @@ export class Main {
333338
);
334339
}
335340

341+
private async initialiseMediaProxy(config: IConfig['mediaProxy']): Promise<void> {
342+
const jwk = JSON.parse(fs.readFileSync(config.signingKeyPath, "utf8").toString());
343+
const signingKey = await webcrypto.subtle.importKey('jwk', jwk, {
344+
name: 'HMAC',
345+
hash: 'SHA-512',
346+
}, true, ['sign', 'verify']);
347+
const publicUrl = new URL(config.publicUrl);
348+
349+
this.mediaProxy = new MediaProxy({
350+
publicUrl,
351+
signingKey,
352+
ttl: config.ttlSeconds * 1000
353+
}, this.bridge.getIntent().matrixClient);
354+
await this.mediaProxy.start(config.bindPort);
355+
}
356+
336357
public teamIsUsingRtm(teamId: string): boolean {
337358
return (this.slackRtm !== undefined) && this.slackRtm.teamIsUsingRtm(teamId);
338359
}
@@ -1142,6 +1163,14 @@ export class Main {
11421163
path: "/ready",
11431164
});
11441165

1166+
if (this.config.mediaProxy) {
1167+
await this.initialiseMediaProxy(this.config.mediaProxy).catch(err => {
1168+
throw Error(`Failed to start Media Proxy: ${err}`);
1169+
});
1170+
} else {
1171+
log.warn("Media Proxy not configured: media bridging to Slack won't work on servers requiring authenticated media (default since Synapse v1.120.0)");
1172+
}
1173+
11451174

11461175
await this.pingBridge();
11471176

src/generate-signing-key.js

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
const webcrypto = require('node:crypto');
2+
3+
async function main() {
4+
const key = await webcrypto.subtle.generateKey({
5+
name: 'HMAC',
6+
hash: 'SHA-512',
7+
}, true, ['sign', 'verify']);
8+
console.log(JSON.stringify(await webcrypto.subtle.exportKey('jwk', key), undefined, 4));
9+
}
10+
11+
main().then(() => process.exit(0)).catch(err => { throw err });

src/substitutions.ts

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -173,7 +173,12 @@ class Substitutions {
173173
// in this case.
174174
return null;
175175
}
176-
const url = main.getUrlForMxc(event.content.url, main.encryptRoom);
176+
let url: string;
177+
if (main.mediaProxy) {
178+
url = await main.mediaProxy.generateMediaUrl(event.content.url).then(url => url.toString());
179+
} else {
180+
url = main.getUrlForMxc(event.content.url, main.encryptRoom);
181+
}
177182
if (main.encryptRoom) {
178183
return {
179184
encrypted_file: url,

yarn.lock

Lines changed: 26 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1120,12 +1120,10 @@ agent-base@6:
11201120
dependencies:
11211121
debug "4"
11221122

1123-
agent-base@^7.0.2:
1124-
version "7.1.1"
1125-
resolved "https://registry.yarnpkg.com/agent-base/-/agent-base-7.1.1.tgz#bdbded7dfb096b751a2a087eeeb9664725b2e317"
1126-
integrity sha512-H0TSyFNDMomMNJQBn8wFV5YC/2eJ+VXECwOadZJT554xP6cODZHPX3H9QMQECxvrgiSOP1pHjy1sMWQVYJOUOA==
1127-
dependencies:
1128-
debug "^4.3.4"
1123+
agent-base@^7.1.2:
1124+
version "7.1.3"
1125+
resolved "https://registry.yarnpkg.com/agent-base/-/agent-base-7.1.3.tgz#29435eb821bc4194633a5b89e5bc4703bafc25a1"
1126+
integrity sha512-jRR5wdylq8CkOe6hei19GGZnxM6rBGwFl3Bg0YItGDimvjGtAvdZk4Pu6Cl4u4Igsws4a1fd1Vq3ezrhn4KmFw==
11291127

11301128
aggregate-error@^3.0.0:
11311129
version "3.1.0"
@@ -3009,12 +3007,20 @@ https-proxy-agent@^5.0.1:
30093007
agent-base "6"
30103008
debug "4"
30113009

3012-
https-proxy-agent@^7.0.4:
3013-
version "7.0.4"
3014-
resolved "https://registry.yarnpkg.com/https-proxy-agent/-/https-proxy-agent-7.0.4.tgz#8e97b841a029ad8ddc8731f26595bad868cb4168"
3015-
integrity sha512-wlwpilI7YdjSkWaQ/7omYBMTliDcmCN8OLihO6I9B86g06lMyAoqgoDpV0XqoaPOKj+0DIdAvnsWfyAAhmimcg==
3010+
https-proxy-agent@^7.0.4, https-proxy-agent@^7.0.5:
3011+
version "7.0.6"
3012+
resolved "https://registry.yarnpkg.com/https-proxy-agent/-/https-proxy-agent-7.0.6.tgz#da8dfeac7da130b05c2ba4b59c9b6cd66611a6b9"
3013+
integrity sha512-vK9P5/iUfdl95AI+JVyUuIcVtd4ofvtrOr3HNtM2yxC9bnMbEdp3x01OhQNnjb8IJYi38VlTE3mBXwcfvywuSw==
30163014
dependencies:
3017-
agent-base "^7.0.2"
3015+
agent-base "^7.1.2"
3016+
debug "4"
3017+
3018+
https-proxy-agent@^7.0.5:
3019+
version "7.0.6"
3020+
resolved "https://registry.yarnpkg.com/https-proxy-agent/-/https-proxy-agent-7.0.6.tgz#da8dfeac7da130b05c2ba4b59c9b6cd66611a6b9"
3021+
integrity sha512-vK9P5/iUfdl95AI+JVyUuIcVtd4ofvtrOr3HNtM2yxC9bnMbEdp3x01OhQNnjb8IJYi38VlTE3mBXwcfvywuSw==
3022+
dependencies:
3023+
agent-base "^7.1.2"
30183024
debug "4"
30193025

30203026
@@ -3707,10 +3713,15 @@ make-error@^1.1.1:
37073713
resolved "https://registry.yarnpkg.com/make-error/-/make-error-1.3.6.tgz#2eb2e37ea9b67c4891f684a1394799af484cf7a2"
37083714
integrity sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw==
37093715

3710-
matrix-appservice-bridge@^10.1.0:
3711-
version "10.1.0"
3712-
resolved "https://registry.yarnpkg.com/matrix-appservice-bridge/-/matrix-appservice-bridge-10.1.0.tgz#8d23bb4c671822684e3121224f1df339f0615b9d"
3713-
integrity sha512-WiyovdQv3WfguffCTTycZ+tM+gwc4DvxSS6em0q5kjdCYiw+ogXezTTkUZZ2QBsIqmgVzF96UQC8PuFS7iWoBA==
3716+
math-intrinsics@^1.0.0, math-intrinsics@^1.1.0:
3717+
version "1.1.0"
3718+
resolved "https://registry.yarnpkg.com/math-intrinsics/-/math-intrinsics-1.1.0.tgz#a0dd74be81e2aa5c2f27e65ce283605ee4e2b7f9"
3719+
integrity sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g==
3720+
3721+
matrix-appservice-bridge@^10.3.1:
3722+
version "10.3.1"
3723+
resolved "https://registry.yarnpkg.com/matrix-appservice-bridge/-/matrix-appservice-bridge-10.3.1.tgz#8f45b616a69ddd599bc8e4fb9b60c950cce10550"
3724+
integrity sha512-umBLAqLUdm6TefEdQuHUE0QfSmbtJf+LnHDYRM5XwpMjScIXQ/5pI6559gVQrxVVT5T58jbNuoJCz2+8+XLr3Q==
37143725
dependencies:
37153726
"@alloc/quick-lru" "^5.2.0"
37163727
"@types/nedb" "^1.8.16"

0 commit comments

Comments
 (0)