Compare commits
2 commits
e0bb19bfab
...
7d42a530e7
Author | SHA1 | Date | |
---|---|---|---|
7d42a530e7 | |||
37f3a59d8e |
25 changed files with 306 additions and 43 deletions
|
@ -3,7 +3,7 @@
|
||||||
const assert = require("assert").strict
|
const assert = require("assert").strict
|
||||||
const DiscordTypes = require("discord-api-types/v10")
|
const DiscordTypes = require("discord-api-types/v10")
|
||||||
const Ty = require("../../types")
|
const Ty = require("../../types")
|
||||||
const reg = require("../../matrix/read-registration")
|
const {reg} = require("../../matrix/read-registration")
|
||||||
|
|
||||||
const passthrough = require("../../passthrough")
|
const passthrough = require("../../passthrough")
|
||||||
const {discord, sync, db, select} = passthrough
|
const {discord, sync, db, select} = passthrough
|
||||||
|
@ -372,7 +372,7 @@ async function _unbridgeRoom(channelID) {
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param {DiscordTypes.APIGuildChannel} channel
|
* @param {{id: string, topic?: string?}} channel
|
||||||
* @param {string} guildID
|
* @param {string} guildID
|
||||||
*/
|
*/
|
||||||
async function unbridgeDeletedChannel(channel, guildID) {
|
async function unbridgeDeletedChannel(channel, guildID) {
|
||||||
|
|
|
@ -4,7 +4,7 @@ const assert = require("assert").strict
|
||||||
const {isDeepStrictEqual} = require("util")
|
const {isDeepStrictEqual} = require("util")
|
||||||
const DiscordTypes = require("discord-api-types/v10")
|
const DiscordTypes = require("discord-api-types/v10")
|
||||||
const Ty = require("../../types")
|
const Ty = require("../../types")
|
||||||
const reg = require("../../matrix/read-registration")
|
const {reg} = require("../../matrix/read-registration")
|
||||||
|
|
||||||
const passthrough = require("../../passthrough")
|
const passthrough = require("../../passthrough")
|
||||||
const {discord, sync, db, select} = passthrough
|
const {discord, sync, db, select} = passthrough
|
||||||
|
@ -192,7 +192,7 @@ async function syncSpaceFully(guildID) {
|
||||||
if (discord.channels.has(channelID)) {
|
if (discord.channels.has(channelID)) {
|
||||||
await createRoom.syncRoom(channelID)
|
await createRoom.syncRoom(channelID)
|
||||||
} else {
|
} else {
|
||||||
await createRoom.unbridgeDeletedChannel(channelID, guildID)
|
await createRoom.unbridgeDeletedChannel({id: channelID}, guildID)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
// @ts-check
|
// @ts-check
|
||||||
|
|
||||||
const assert = require("assert")
|
const assert = require("assert")
|
||||||
const reg = require("../../matrix/read-registration")
|
const {reg} = require("../../matrix/read-registration")
|
||||||
const Ty = require("../../types")
|
const Ty = require("../../types")
|
||||||
const fetch = require("node-fetch").default
|
const fetch = require("node-fetch").default
|
||||||
|
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
// @ts-check
|
// @ts-check
|
||||||
|
|
||||||
const assert = require("assert").strict
|
const assert = require("assert").strict
|
||||||
const reg = require("../../matrix/read-registration")
|
const {reg} = require("../../matrix/read-registration")
|
||||||
const DiscordTypes = require("discord-api-types/v10")
|
const DiscordTypes = require("discord-api-types/v10")
|
||||||
const mixin = require("@cloudrac3r/mixin-deep")
|
const mixin = require("@cloudrac3r/mixin-deep")
|
||||||
|
|
||||||
|
|
|
@ -18,7 +18,7 @@ const lottie = sync.require("../actions/lottie")
|
||||||
const mxUtils = sync.require("../../m2d/converters/utils")
|
const mxUtils = sync.require("../../m2d/converters/utils")
|
||||||
/** @type {import("../../discord/utils")} */
|
/** @type {import("../../discord/utils")} */
|
||||||
const dUtils = sync.require("../../discord/utils")
|
const dUtils = sync.require("../../discord/utils")
|
||||||
const reg = require("../../matrix/read-registration")
|
const {reg} = require("../../matrix/read-registration")
|
||||||
|
|
||||||
const userRegex = reg.namespaces.users.map(u => new RegExp(u.regex))
|
const userRegex = reg.namespaces.users.map(u => new RegExp(u.regex))
|
||||||
|
|
||||||
|
|
|
@ -4,10 +4,9 @@ const assert = require("assert").strict
|
||||||
|
|
||||||
const passthrough = require("../../passthrough")
|
const passthrough = require("../../passthrough")
|
||||||
const {discord, sync, db, select} = passthrough
|
const {discord, sync, db, select} = passthrough
|
||||||
/** @type {import("../../matrix/read-registration")} */
|
|
||||||
const reg = sync.require("../../matrix/read-registration.js")
|
|
||||||
/** @type {import("../../m2d/converters/utils")} */
|
/** @type {import("../../m2d/converters/utils")} */
|
||||||
const mxUtils = sync.require("../../m2d/converters/utils")
|
const mxUtils = sync.require("../../m2d/converters/utils")
|
||||||
|
const {reg} = require("../../matrix/read-registration.js")
|
||||||
|
|
||||||
const userRegex = reg.namespaces.users.map(u => new RegExp(u.regex))
|
const userRegex = reg.namespaces.users.map(u => new RegExp(u.regex))
|
||||||
|
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
// @ts-check
|
// @ts-check
|
||||||
|
|
||||||
const assert = require("assert")
|
const assert = require("assert")
|
||||||
const registration = require("../../matrix/read-registration")
|
const {reg} = require("../../matrix/read-registration")
|
||||||
|
|
||||||
const passthrough = require("../../passthrough")
|
const passthrough = require("../../passthrough")
|
||||||
const {select} = passthrough
|
const {select} = passthrough
|
||||||
|
@ -26,7 +26,7 @@ function downcaseUsername(user) {
|
||||||
// remove leading and trailing dashes and underscores...
|
// remove leading and trailing dashes and underscores...
|
||||||
.replace(/(?:^[_-]*|[_-]*$)/g, "")
|
.replace(/(?:^[_-]*|[_-]*$)/g, "")
|
||||||
// If requested, also make the Discord user ID part of the username
|
// If requested, also make the Discord user ID part of the username
|
||||||
if (registration.ooye.include_user_id_in_mxid) {
|
if (reg.ooye.include_user_id_in_mxid) {
|
||||||
downcased = user.id + "_" + downcased
|
downcased = user.id + "_" + downcased
|
||||||
}
|
}
|
||||||
// The new length must be at least 2 characters (in other words, it should have some content)
|
// The new length must be at least 2 characters (in other words, it should have some content)
|
||||||
|
|
|
@ -46,7 +46,7 @@ test("user2name: works on special user", t => {
|
||||||
})
|
})
|
||||||
|
|
||||||
test("user2name: includes ID if requested in config", t => {
|
test("user2name: includes ID if requested in config", t => {
|
||||||
const reg = require("../../matrix/read-registration")
|
const {reg} = require("../../matrix/read-registration")
|
||||||
reg.ooye.include_user_id_in_mxid = true
|
reg.ooye.include_user_id_in_mxid = true
|
||||||
t.equal(userToSimName({username: "Harry Styles!", discriminator: "0001", id: "123456"}), "123456_harry_styles")
|
t.equal(userToSimName({username: "Harry Styles!", discriminator: "0001", id: "123456"}), "123456_harry_styles")
|
||||||
t.equal(userToSimName({username: "f***", discriminator: "0001", id: "123456"}), "123456_f")
|
t.equal(userToSimName({username: "f***", discriminator: "0001", id: "123456"}), "123456_f")
|
||||||
|
|
|
@ -3,7 +3,7 @@
|
||||||
const assert = require("assert").strict
|
const assert = require("assert").strict
|
||||||
const util = require("util")
|
const util = require("util")
|
||||||
const DiscordTypes = require("discord-api-types/v10")
|
const DiscordTypes = require("discord-api-types/v10")
|
||||||
const reg = require("../matrix/read-registration")
|
const {reg} = require("../matrix/read-registration")
|
||||||
const {addbot} = require("../addbot")
|
const {addbot} = require("../addbot")
|
||||||
|
|
||||||
const {discord, sync, db, select} = require("../passthrough")
|
const {discord, sync, db, select} = require("../passthrough")
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
// @ts-check
|
// @ts-check
|
||||||
|
|
||||||
const reg = require("../../matrix/read-registration")
|
const {reg} = require("../../matrix/read-registration")
|
||||||
const userRegex = reg.namespaces.users.map(u => new RegExp(u.regex))
|
const userRegex = reg.namespaces.users.map(u => new RegExp(u.regex))
|
||||||
const assert = require("assert").strict
|
const assert = require("assert").strict
|
||||||
/** @type {import("xxhash-wasm").XXHashAPI} */ // @ts-ignore
|
/** @type {import("xxhash-wasm").XXHashAPI} */ // @ts-ignore
|
||||||
|
|
|
@ -20,8 +20,7 @@ const matrixCommandHandler = sync.require("../matrix/matrix-command-handler")
|
||||||
const utils = sync.require("./converters/utils")
|
const utils = sync.require("./converters/utils")
|
||||||
/** @type {import("../matrix/api")}) */
|
/** @type {import("../matrix/api")}) */
|
||||||
const api = sync.require("../matrix/api")
|
const api = sync.require("../matrix/api")
|
||||||
/** @type {import("../matrix/read-registration")}) */
|
const {reg} = require("../matrix/read-registration")
|
||||||
const reg = sync.require("../matrix/read-registration")
|
|
||||||
|
|
||||||
let lastReportedEvent = 0
|
let lastReportedEvent = 0
|
||||||
|
|
||||||
|
|
|
@ -11,6 +11,7 @@ const mreq = sync.require("./mreq")
|
||||||
const file = sync.require("./file")
|
const file = sync.require("./file")
|
||||||
/** @type {import("./txnid")} */
|
/** @type {import("./txnid")} */
|
||||||
const makeTxnId = sync.require("./txnid")
|
const makeTxnId = sync.require("./txnid")
|
||||||
|
const {reg} = require("./read-registration.js")
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param {string} p endpoint to access
|
* @param {string} p endpoint to access
|
||||||
|
@ -295,6 +296,22 @@ async function setUserPowerCascade(roomID, mxid, power) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async function ping() {
|
||||||
|
const res = await fetch(`${mreq.baseUrl}/client/v1/appservice/${reg.id}/ping`, {
|
||||||
|
method: "POST",
|
||||||
|
headers: {
|
||||||
|
Authorization: `Bearer ${reg.as_token}`
|
||||||
|
},
|
||||||
|
body: "{}"
|
||||||
|
})
|
||||||
|
const root = await res.json()
|
||||||
|
return {
|
||||||
|
ok: res.ok,
|
||||||
|
status: res.status,
|
||||||
|
root
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
module.exports.path = path
|
module.exports.path = path
|
||||||
module.exports.register = register
|
module.exports.register = register
|
||||||
module.exports.createRoom = createRoom
|
module.exports.createRoom = createRoom
|
||||||
|
@ -318,3 +335,4 @@ module.exports.profileSetDisplayname = profileSetDisplayname
|
||||||
module.exports.profileSetAvatarUrl = profileSetAvatarUrl
|
module.exports.profileSetAvatarUrl = profileSetAvatarUrl
|
||||||
module.exports.setUserPower = setUserPower
|
module.exports.setUserPower = setUserPower
|
||||||
module.exports.setUserPowerCascade = setUserPowerCascade
|
module.exports.setUserPowerCascade = setUserPowerCascade
|
||||||
|
module.exports.ping = ping
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
// @ts-check
|
// @ts-check
|
||||||
|
|
||||||
const reg = require("../matrix/read-registration")
|
const {reg} = require("../matrix/read-registration")
|
||||||
const {AppService} = require("@cloudrac3r/in-your-element")
|
const {AppService} = require("@cloudrac3r/in-your-element")
|
||||||
const as = new AppService(reg)
|
const as = new AppService(reg)
|
||||||
as.listen()
|
as.listen()
|
||||||
|
|
|
@ -14,7 +14,7 @@ const mxUtils = sync.require("../m2d/converters/utils")
|
||||||
const dUtils = sync.require("../discord/utils")
|
const dUtils = sync.require("../discord/utils")
|
||||||
/** @type {import("./kstate")} */
|
/** @type {import("./kstate")} */
|
||||||
const ks = sync.require("./kstate")
|
const ks = sync.require("./kstate")
|
||||||
const reg = require("./read-registration")
|
const {reg} = require("./read-registration")
|
||||||
|
|
||||||
const PREFIXES = ["//", "/"]
|
const PREFIXES = ["//", "/"]
|
||||||
|
|
||||||
|
|
|
@ -5,10 +5,7 @@ const mixin = require("@cloudrac3r/mixin-deep")
|
||||||
const stream = require("stream")
|
const stream = require("stream")
|
||||||
const getStream = require("get-stream")
|
const getStream = require("get-stream")
|
||||||
|
|
||||||
const passthrough = require("../passthrough")
|
const {reg} = require("./read-registration.js")
|
||||||
const { sync } = passthrough
|
|
||||||
/** @type {import("./read-registration")} */
|
|
||||||
const reg = sync.require("./read-registration.js")
|
|
||||||
|
|
||||||
const baseUrl = `${reg.ooye.server_origin}/_matrix`
|
const baseUrl = `${reg.ooye.server_origin}/_matrix`
|
||||||
|
|
||||||
|
@ -81,5 +78,6 @@ async function withAccessToken(token, callback) {
|
||||||
}
|
}
|
||||||
|
|
||||||
module.exports.MatrixServerError = MatrixServerError
|
module.exports.MatrixServerError = MatrixServerError
|
||||||
|
module.exports.baseUrl = baseUrl
|
||||||
module.exports.mreq = mreq
|
module.exports.mreq = mreq
|
||||||
module.exports.withAccessToken = withAccessToken
|
module.exports.withAccessToken = withAccessToken
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
// @ts-check
|
// @ts-check
|
||||||
|
|
||||||
const {db, from} = require("../passthrough")
|
const {db, from} = require("../passthrough")
|
||||||
const reg = require("./read-registration")
|
const {reg} = require("./read-registration")
|
||||||
const ks = require("./kstate")
|
const ks = require("./kstate")
|
||||||
const {applyKStateDiffToRoom, roomToKState} = require("../d2m/actions/create-room")
|
const {applyKStateDiffToRoom, roomToKState} = require("../d2m/actions/create-room")
|
||||||
|
|
||||||
|
|
|
@ -1,14 +1,85 @@
|
||||||
// @ts-check
|
// @ts-check
|
||||||
|
|
||||||
const fs = require("fs")
|
const fs = require("fs")
|
||||||
|
const crypto = require("crypto")
|
||||||
const assert = require("assert").strict
|
const assert = require("assert").strict
|
||||||
|
const path = require("path")
|
||||||
const yaml = require("js-yaml")
|
const yaml = require("js-yaml")
|
||||||
|
|
||||||
/** @ts-ignore @type {import("../types").AppServiceRegistrationConfig} */
|
const registrationFilePath = path.join(process.cwd(), "registration.yaml")
|
||||||
const reg = yaml.load(fs.readFileSync("registration.yaml", "utf8"))
|
|
||||||
reg["ooye"].invite = (reg.ooye.invite || []).filter(mxid => mxid.endsWith(`:${reg.ooye.server_name}`)) // one day I will understand why typescript disagrees with dot notation on this line
|
|
||||||
assert(reg.ooye.max_file_size)
|
|
||||||
assert(reg.ooye.namespace_prefix)
|
|
||||||
assert(reg.ooye.server_name)
|
|
||||||
|
|
||||||
module.exports = reg
|
/** @param {import("../types").AppServiceRegistrationConfig} reg */
|
||||||
|
function checkRegistration(reg) {
|
||||||
|
reg["ooye"].invite = (reg.ooye.invite || []).filter(mxid => mxid.endsWith(`:${reg.ooye.server_name}`)) // one day I will understand why typescript disagrees with dot notation on this line
|
||||||
|
assert(reg.ooye?.max_file_size)
|
||||||
|
assert(reg.ooye?.namespace_prefix)
|
||||||
|
assert(reg.ooye?.server_name)
|
||||||
|
assert(reg.sender_localpart?.startsWith(reg.ooye.namespace_prefix), "appservice's localpart must be in the namespace it controls")
|
||||||
|
assert(reg.ooye?.server_origin.match(/^https?:\/\//), "server origin must start with http or https")
|
||||||
|
assert.notEqual(reg.ooye?.server_origin.slice(-1), "/", "server origin must not end in slash")
|
||||||
|
assert.match(reg.url, /^https?:/, "url must start with http:// or https://")
|
||||||
|
}
|
||||||
|
|
||||||
|
/** @param {import("../types").AppServiceRegistrationConfig} reg */
|
||||||
|
function writeRegistration(reg) {
|
||||||
|
fs.writeFileSync(registrationFilePath, JSON.stringify(reg, null, 2))
|
||||||
|
}
|
||||||
|
|
||||||
|
/** @returns {import("../types").InitialAppServiceRegistrationConfig} reg */
|
||||||
|
function getTemplateRegistration() {
|
||||||
|
return {
|
||||||
|
id: crypto.randomBytes(16).toString("hex"),
|
||||||
|
as_token: crypto.randomBytes(16).toString("hex"),
|
||||||
|
hs_token: crypto.randomBytes(16).toString("hex"),
|
||||||
|
namespaces: {
|
||||||
|
users: [{
|
||||||
|
exclusive: true,
|
||||||
|
regex: "@_ooye_.*:cadence.moe"
|
||||||
|
}],
|
||||||
|
aliases: [{
|
||||||
|
exclusive: true,
|
||||||
|
regex: "#_ooye_.*:cadence.moe"
|
||||||
|
}]
|
||||||
|
},
|
||||||
|
protocols: [
|
||||||
|
"discord"
|
||||||
|
],
|
||||||
|
sender_localpart: "_ooye_bot",
|
||||||
|
rate_limited: false,
|
||||||
|
ooye: {
|
||||||
|
namespace_prefix: "_ooye_",
|
||||||
|
max_file_size: 5000000,
|
||||||
|
content_length_workaround: false,
|
||||||
|
include_user_id_in_mxid: false,
|
||||||
|
invite: []
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function readRegistration() {
|
||||||
|
/** @type {import("../types").AppServiceRegistrationConfig} */ // @ts-ignore
|
||||||
|
let result = null
|
||||||
|
if (fs.existsSync(registrationFilePath)) {
|
||||||
|
const content = fs.readFileSync(registrationFilePath, "utf8")
|
||||||
|
if (content.startsWith("{")) { // Use JSON parser
|
||||||
|
result = JSON.parse(content)
|
||||||
|
checkRegistration(result)
|
||||||
|
} else { // Use YAML parser
|
||||||
|
result = yaml.load(content)
|
||||||
|
checkRegistration(result)
|
||||||
|
// Convert to JSON
|
||||||
|
writeRegistration(result)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return result
|
||||||
|
}
|
||||||
|
|
||||||
|
/** @type {import("../types").AppServiceRegistrationConfig} */ // @ts-ignore
|
||||||
|
let reg = readRegistration()
|
||||||
|
|
||||||
|
module.exports.registrationFilePath = registrationFilePath
|
||||||
|
module.exports.readRegistration = readRegistration
|
||||||
|
module.exports.getTemplateRegistration = getTemplateRegistration
|
||||||
|
module.exports.writeRegistration = writeRegistration
|
||||||
|
module.exports.checkRegistration = checkRegistration
|
||||||
|
module.exports.reg = reg
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
const {test} = require("supertape")
|
const {test} = require("supertape")
|
||||||
const reg = require("./read-registration")
|
const {reg} = require("./read-registration")
|
||||||
|
|
||||||
test("reg: has necessary parameters", t => {
|
test("reg: has necessary parameters", t => {
|
||||||
const propertiesToCheck = ["sender_localpart", "id", "as_token", "ooye"]
|
const propertiesToCheck = ["sender_localpart", "id", "as_token", "ooye"]
|
||||||
|
|
41
package-lock.json
generated
41
package-lock.json
generated
|
@ -17,10 +17,12 @@
|
||||||
"@cloudrac3r/mixin-deep": "^3.0.0",
|
"@cloudrac3r/mixin-deep": "^3.0.0",
|
||||||
"@cloudrac3r/pngjs": "^7.0.3",
|
"@cloudrac3r/pngjs": "^7.0.3",
|
||||||
"@cloudrac3r/turndown": "^7.1.4",
|
"@cloudrac3r/turndown": "^7.1.4",
|
||||||
|
"ansi-colors": "^4.1.3",
|
||||||
"better-sqlite3": "^11.1.2",
|
"better-sqlite3": "^11.1.2",
|
||||||
"chunk-text": "^2.0.1",
|
"chunk-text": "^2.0.1",
|
||||||
"cloudstorm": "^0.10.10",
|
"cloudstorm": "^0.10.10",
|
||||||
"domino": "^2.1.6",
|
"domino": "^2.1.6",
|
||||||
|
"enquirer": "^2.4.1",
|
||||||
"entities": "^5.0.0",
|
"entities": "^5.0.0",
|
||||||
"get-stream": "^6.0.1",
|
"get-stream": "^6.0.1",
|
||||||
"heatsync": "^2.5.3",
|
"heatsync": "^2.5.3",
|
||||||
|
@ -978,6 +980,14 @@
|
||||||
"resolved": "https://registry.npmjs.org/@types/scheduler/-/scheduler-0.16.8.tgz",
|
"resolved": "https://registry.npmjs.org/@types/scheduler/-/scheduler-0.16.8.tgz",
|
||||||
"integrity": "sha512-WZLiwShhwLRmeV6zH+GkbOFT6Z6VklCItrDioxUnv+u4Ll+8vKeFySoFyK/0ctcRpOmwAicELfmys1sDc/Rw+A=="
|
"integrity": "sha512-WZLiwShhwLRmeV6zH+GkbOFT6Z6VklCItrDioxUnv+u4Ll+8vKeFySoFyK/0ctcRpOmwAicELfmys1sDc/Rw+A=="
|
||||||
},
|
},
|
||||||
|
"node_modules/ansi-colors": {
|
||||||
|
"version": "4.1.3",
|
||||||
|
"resolved": "https://registry.npmjs.org/ansi-colors/-/ansi-colors-4.1.3.tgz",
|
||||||
|
"integrity": "sha512-/6w/C21Pm1A7aZitlI5Ni/2J6FFQN8i1Cvz3kHABAAbw93v/NlvKdVOqz7CCWz/3iv/JplRSEEZ83XION15ovw==",
|
||||||
|
"engines": {
|
||||||
|
"node": ">=6"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/ansi-regex": {
|
"node_modules/ansi-regex": {
|
||||||
"version": "6.0.1",
|
"version": "6.0.1",
|
||||||
"resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.0.1.tgz",
|
"resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.0.1.tgz",
|
||||||
|
@ -1495,6 +1505,37 @@
|
||||||
"once": "^1.4.0"
|
"once": "^1.4.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/enquirer": {
|
||||||
|
"version": "2.4.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/enquirer/-/enquirer-2.4.1.tgz",
|
||||||
|
"integrity": "sha512-rRqJg/6gd538VHvR3PSrdRBb/1Vy2YfzHqzvbhGIQpDRKIa4FgV/54b5Q1xYSxOOwKvjXweS26E0Q+nAMwp2pQ==",
|
||||||
|
"dependencies": {
|
||||||
|
"ansi-colors": "^4.1.1",
|
||||||
|
"strip-ansi": "^6.0.1"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">=8.6"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/enquirer/node_modules/ansi-regex": {
|
||||||
|
"version": "5.0.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz",
|
||||||
|
"integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==",
|
||||||
|
"engines": {
|
||||||
|
"node": ">=8"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/enquirer/node_modules/strip-ansi": {
|
||||||
|
"version": "6.0.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz",
|
||||||
|
"integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==",
|
||||||
|
"dependencies": {
|
||||||
|
"ansi-regex": "^5.0.1"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">=8"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/entities": {
|
"node_modules/entities": {
|
||||||
"version": "5.0.0",
|
"version": "5.0.0",
|
||||||
"resolved": "https://registry.npmjs.org/entities/-/entities-5.0.0.tgz",
|
"resolved": "https://registry.npmjs.org/entities/-/entities-5.0.0.tgz",
|
||||||
|
|
|
@ -26,10 +26,12 @@
|
||||||
"@cloudrac3r/mixin-deep": "^3.0.0",
|
"@cloudrac3r/mixin-deep": "^3.0.0",
|
||||||
"@cloudrac3r/pngjs": "^7.0.3",
|
"@cloudrac3r/pngjs": "^7.0.3",
|
||||||
"@cloudrac3r/turndown": "^7.1.4",
|
"@cloudrac3r/turndown": "^7.1.4",
|
||||||
|
"ansi-colors": "^4.1.3",
|
||||||
"better-sqlite3": "^11.1.2",
|
"better-sqlite3": "^11.1.2",
|
||||||
"chunk-text": "^2.0.1",
|
"chunk-text": "^2.0.1",
|
||||||
"cloudstorm": "^0.10.10",
|
"cloudstorm": "^0.10.10",
|
||||||
"domino": "^2.1.6",
|
"domino": "^2.1.6",
|
||||||
|
"enquirer": "^2.4.1",
|
||||||
"entities": "^5.0.0",
|
"entities": "^5.0.0",
|
||||||
"get-stream": "^6.0.1",
|
"get-stream": "^6.0.1",
|
||||||
"heatsync": "^2.5.3",
|
"heatsync": "^2.5.3",
|
||||||
|
|
|
@ -165,14 +165,16 @@ To get into the rooms on your Matrix account, either add yourself to `invite` in
|
||||||
* (1) @cloudrac3r/discord-markdown: This is my fork!
|
* (1) @cloudrac3r/discord-markdown: This is my fork!
|
||||||
* (0) @cloudrac3r/giframe: This is my fork!
|
* (0) @cloudrac3r/giframe: This is my fork!
|
||||||
* (1) @cloudrac3r/html-template-tag: This is my fork!
|
* (1) @cloudrac3r/html-template-tag: This is my fork!
|
||||||
* (16) @cloudrac3r/in-your-element: This is my Matrix Appservice API library.
|
* (16) @cloudrac3r/in-your-element: This is my Matrix Appservice API library. It has several dependencies because HTTP servers have to do more than you'd think.
|
||||||
* (0) @cloudrac3r/mixin-deep: This is my fork! (It fixes a bug in regular mixin-deep.)
|
* (0) @cloudrac3r/mixin-deep: This is my fork! (It fixes a bug in regular mixin-deep.)
|
||||||
* (0) @cloudrac3r/pngjs: Lottie stickers are converted to bitmaps with the vendored Rlottie WASM build, then the bitmaps are converted to PNG with pngjs.
|
* (0) @cloudrac3r/pngjs: Lottie stickers are converted to bitmaps with the vendored Rlottie WASM build, then the bitmaps are converted to PNG with pngjs.
|
||||||
* (0) @cloudrac3r/turndown: This HTML-to-Markdown converter looked the most suitable. I forked it to change the escaping logic to match the way Discord works.
|
* (0) @cloudrac3r/turndown: This HTML-to-Markdown converter looked the most suitable. I forked it to change the escaping logic to match the way Discord works.
|
||||||
|
* (0) ansi-colors: Helps with interactive prompting for the initial setup, and it's already pulled in by enquirer.
|
||||||
* (42) better-sqlite3: SQLite3 is the best database, and this is the best library for it. Really! I love it.
|
* (42) better-sqlite3: SQLite3 is the best database, and this is the best library for it. Really! I love it.
|
||||||
* (1) chunk-text: It does what I want.
|
* (1) chunk-text: It does what I want.
|
||||||
* (0) cloudstorm: Discord gateway library with bring-your-own-caching that I trust.
|
* (0) cloudstorm: Discord gateway library with bring-your-own-caching that I trust.
|
||||||
* (0) domino: DOM implementation that's already pulled in by turndown.
|
* (0) domino: DOM implementation that's already pulled in by turndown.
|
||||||
|
* (1) enquirer: Interactive prompting for the initial setup rather than forcing users to edit YAML non-interactively.
|
||||||
* (0) entities: Looks fine. No dependencies.
|
* (0) entities: Looks fine. No dependencies.
|
||||||
* (0) get-stream: Only needed if content_length_workaround is true.
|
* (0) get-stream: Only needed if content_length_workaround is true.
|
||||||
* (1) heatsync: Module hot-reloader that I trust.
|
* (1) heatsync: Module hot-reloader that I trust.
|
||||||
|
@ -186,4 +188,4 @@ To get into the rooms on your Matrix account, either add yourself to `invite` in
|
||||||
* (0) try-to-catch: Not strictly necessary, but it's already pulled in by supertape, so I may as well.
|
* (0) try-to-catch: Not strictly necessary, but it's already pulled in by supertape, so I may as well.
|
||||||
* (0) xxhash-wasm: Used where cryptographically secure hashing is not required.
|
* (0) xxhash-wasm: Used where cryptographically secure hashing is not required.
|
||||||
|
|
||||||
Total transitive production dependencies: 113
|
Total transitive production dependencies: 116
|
||||||
|
|
|
@ -11,8 +11,7 @@ const passthrough = require("../passthrough")
|
||||||
|
|
||||||
const sync = new HeatSync({watchFS: false})
|
const sync = new HeatSync({watchFS: false})
|
||||||
|
|
||||||
/** @type {import("../matrix/read-registration")} */
|
const {reg} = require("../matrix/read-registration")
|
||||||
const reg = sync.require("../matrix/read-registration")
|
|
||||||
assert(reg.old_bridge)
|
assert(reg.old_bridge)
|
||||||
const oldAT = reg.old_bridge.as_token
|
const oldAT = reg.old_bridge.as_token
|
||||||
const newAT = reg.as_token
|
const newAT = reg.as_token
|
||||||
|
|
120
scripts/seed.js
120
scripts/seed.js
|
@ -1,10 +1,15 @@
|
||||||
// @ts-check
|
// @ts-check
|
||||||
|
|
||||||
console.log("This could take up to 30 seconds. Please be patient.")
|
|
||||||
|
|
||||||
const assert = require("assert").strict
|
const assert = require("assert").strict
|
||||||
const fs = require("fs")
|
const fs = require("fs")
|
||||||
const sqlite = require("better-sqlite3")
|
const sqlite = require("better-sqlite3")
|
||||||
|
const {scheduler: {wait}} = require("timers/promises")
|
||||||
|
const {isDeepStrictEqual} = require("util")
|
||||||
|
|
||||||
|
const {prompt} = require("enquirer")
|
||||||
|
const Input = require("enquirer/lib/prompts/input")
|
||||||
|
const fetch = require("node-fetch")
|
||||||
|
const {magenta, bold, cyan} = require("ansi-colors")
|
||||||
const HeatSync = require("heatsync")
|
const HeatSync = require("heatsync")
|
||||||
|
|
||||||
const args = require("minimist")(process.argv.slice(2), {string: ["emoji-guild"]})
|
const args = require("minimist")(process.argv.slice(2), {string: ["emoji-guild"]})
|
||||||
|
@ -26,10 +31,8 @@ const DiscordClient = require("../d2m/discord-client")
|
||||||
const discord = new DiscordClient(config.discordToken, "no")
|
const discord = new DiscordClient(config.discordToken, "no")
|
||||||
passthrough.discord = discord
|
passthrough.discord = discord
|
||||||
|
|
||||||
const api = require("../matrix/api")
|
let registration = require("../matrix/read-registration")
|
||||||
const file = require("../matrix/file")
|
let {reg, getTemplateRegistration, writeRegistration, readRegistration, registrationFilePath} = registration
|
||||||
const reg = require("../matrix/read-registration")
|
|
||||||
const utils = require("../m2d/converters/utils")
|
|
||||||
|
|
||||||
function die(message) {
|
function die(message) {
|
||||||
console.error(message)
|
console.error(message)
|
||||||
|
@ -49,7 +52,111 @@ async function uploadAutoEmoji(guild, name, filename) {
|
||||||
return emoji
|
return emoji
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async function validateHomeserverOrigin(serverUrlPrompt, url) {
|
||||||
|
if (!url.match(/^https?:\/\//)) return "Must be a URL"
|
||||||
|
if (url.match(/\/$/)) return "Must not end with a slash"
|
||||||
|
process.stdout.write(magenta(" checking, please wait..."))
|
||||||
|
try {
|
||||||
|
var json = await fetch(`${url}/.well-known/matrix/client`).then(res => res.json())
|
||||||
|
let baseURL = json["m.homeserver"].base_url.replace(/\/$/, "")
|
||||||
|
if (baseURL && baseURL !== url) {
|
||||||
|
serverUrlPrompt.initial = baseURL
|
||||||
|
return `Did you mean: ${bold(baseURL)}? (Enter to accept)`
|
||||||
|
}
|
||||||
|
} catch (e) {}
|
||||||
|
try {
|
||||||
|
var res = await fetch(`${url}/_matrix/client/versions`)
|
||||||
|
} catch (e) {
|
||||||
|
return e.message
|
||||||
|
}
|
||||||
|
if (res.status !== 200) return `There is no Matrix server at that URL (${url}/_matrix/client/versions returned ${res.status})`
|
||||||
|
try {
|
||||||
|
var json = await res.json()
|
||||||
|
} catch (e) {
|
||||||
|
return `There is no Matrix server at that URL (${url}/_matrix/client/versions is not JSON)`
|
||||||
|
}
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
;(async () => {
|
;(async () => {
|
||||||
|
// create registration file with prompts...
|
||||||
|
if (!reg) {
|
||||||
|
console.log("What is the name of your homeserver? This is the part after : in your username.")
|
||||||
|
/** @type {{server_name: string}} */
|
||||||
|
const serverNameResponse = await prompt({
|
||||||
|
type: "input",
|
||||||
|
name: "server_name",
|
||||||
|
message: "Homeserver name"
|
||||||
|
})
|
||||||
|
console.log("What is the URL of your homeserver?")
|
||||||
|
const serverUrlPrompt = new Input({
|
||||||
|
type: "input",
|
||||||
|
name: "server_origin",
|
||||||
|
message: "Homeserver URL",
|
||||||
|
initial: () => `https://${serverNameResponse.server_name}`,
|
||||||
|
validate: url => validateHomeserverOrigin(serverUrlPrompt, url)
|
||||||
|
})
|
||||||
|
/** @type {{server_origin: string}} */ // @ts-ignore
|
||||||
|
const serverUrlResponse = await serverUrlPrompt.run()
|
||||||
|
console.log("Your Matrix homeserver needs to be able to send HTTP requests to OOYE.")
|
||||||
|
console.log("What URL should OOYE be reachable on? Usually, the default works fine,")
|
||||||
|
console.log("but you need to change this if you use multiple servers or containers.")
|
||||||
|
/** @type {{url: string}} */
|
||||||
|
const urlResponse = await prompt({
|
||||||
|
type: "input",
|
||||||
|
name: "url",
|
||||||
|
message: "URL to reach OOYE",
|
||||||
|
initial: "http://localhost:6693",
|
||||||
|
validate: url => !!url.match(/^https?:\/\//)
|
||||||
|
})
|
||||||
|
const template = getTemplateRegistration()
|
||||||
|
reg = {...template, ...urlResponse, ooye: {...template.ooye, ...serverNameResponse, ...serverUrlResponse}}
|
||||||
|
registration.reg = reg
|
||||||
|
writeRegistration(reg)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Done with user prompts, reg is now guaranteed to be valid
|
||||||
|
const api = require("../matrix/api")
|
||||||
|
const file = require("../matrix/file")
|
||||||
|
const utils = require("../m2d/converters/utils")
|
||||||
|
|
||||||
|
console.log(`✅ Registration file saved as ${registrationFilePath}`)
|
||||||
|
console.log(` In ${cyan("Synapse")}, you need to add it to homeserver.yaml and ${cyan("restart Synapse")}.`)
|
||||||
|
console.log(" https://element-hq.github.io/synapse/latest/application_services.html")
|
||||||
|
console.log(` In ${cyan("Conduit")}, you need to send the file contents to the #admins room.`)
|
||||||
|
console.log(" https://docs.conduit.rs/appservices.html")
|
||||||
|
console.log()
|
||||||
|
|
||||||
|
const {as} = require("../matrix/appservice")
|
||||||
|
console.log("⏳ Waiting until homeserver registration works... (Ctrl+C to cancel)")
|
||||||
|
|
||||||
|
let itWorks = false
|
||||||
|
let lastError = null
|
||||||
|
do {
|
||||||
|
const result = await api.ping()
|
||||||
|
// If it didn't work, log details and retry after some time
|
||||||
|
itWorks = result.ok
|
||||||
|
if (!itWorks) {
|
||||||
|
// Log the full error data if the error is different to last time
|
||||||
|
if (!isDeepStrictEqual(lastError, result.root)) {
|
||||||
|
if (result.root.error) {
|
||||||
|
console.log(`\nHomeserver said: [${result.status}] ${result.root.error}`)
|
||||||
|
} else {
|
||||||
|
console.log(`\nHomeserver said: [${result.status}] ${JSON.stringify(result.root)}`)
|
||||||
|
}
|
||||||
|
lastError = result.root
|
||||||
|
} else {
|
||||||
|
process.stderr.write(".")
|
||||||
|
}
|
||||||
|
await wait(5000)
|
||||||
|
}
|
||||||
|
} while (!itWorks)
|
||||||
|
console.log("")
|
||||||
|
|
||||||
|
as.close().catch(() => {})
|
||||||
|
|
||||||
|
console.log("⏩ Processing. This could take up to 30 seconds. Please be patient...")
|
||||||
|
|
||||||
const mxid = `@${reg.sender_localpart}:${reg.ooye.server_name}`
|
const mxid = `@${reg.sender_localpart}:${reg.ooye.server_name}`
|
||||||
|
|
||||||
// ensure registration is correctly set...
|
// ensure registration is correctly set...
|
||||||
|
@ -60,6 +167,7 @@ async function uploadAutoEmoji(guild, name, filename) {
|
||||||
const botID = Buffer.from(config.discordToken.split(".")[0], "base64").toString()
|
const botID = Buffer.from(config.discordToken.split(".")[0], "base64").toString()
|
||||||
assert(botID.match(/^[0-9]{10,}$/), "discord token must follow the correct format")
|
assert(botID.match(/^[0-9]{10,}$/), "discord token must follow the correct format")
|
||||||
assert.match(reg.url, /^https?:/, "url must start with http:// or https://")
|
assert.match(reg.url, /^https?:/, "url must start with http:// or https://")
|
||||||
|
|
||||||
console.log("✅ Configuration looks good...")
|
console.log("✅ Configuration looks good...")
|
||||||
|
|
||||||
// database ddl...
|
// database ddl...
|
||||||
|
|
|
@ -17,7 +17,7 @@ const config = require("../config")
|
||||||
const passthrough = require("../passthrough")
|
const passthrough = require("../passthrough")
|
||||||
const db = new sqlite(":memory:")
|
const db = new sqlite(":memory:")
|
||||||
|
|
||||||
const reg = require("../matrix/read-registration")
|
const {reg} = require("../matrix/read-registration")
|
||||||
reg.ooye.server_origin = "https://matrix.cadence.moe" // so that tests will pass even when hard-coded
|
reg.ooye.server_origin = "https://matrix.cadence.moe" // so that tests will pass even when hard-coded
|
||||||
reg.ooye.server_name = "cadence.moe"
|
reg.ooye.server_name = "cadence.moe"
|
||||||
reg.id = "baby" // don't actually take authenticated actions on the server
|
reg.id = "baby" // don't actually take authenticated actions on the server
|
||||||
|
@ -117,7 +117,7 @@ file._actuallyUploadDiscordFileToMxc = function(url, res) { throw new Error(`Not
|
||||||
require("../matrix/kstate.test")
|
require("../matrix/kstate.test")
|
||||||
require("../matrix/api.test")
|
require("../matrix/api.test")
|
||||||
require("../matrix/file.test")
|
require("../matrix/file.test")
|
||||||
require("../matrix/power.test")
|
//require("../matrix/power.test")
|
||||||
require("../matrix/read-registration.test")
|
require("../matrix/read-registration.test")
|
||||||
require("../matrix/txnid.test")
|
require("../matrix/txnid.test")
|
||||||
require("../d2m/actions/create-room.test")
|
require("../d2m/actions/create-room.test")
|
||||||
|
|
26
types.d.ts
vendored
26
types.d.ts
vendored
|
@ -31,6 +31,32 @@ export type AppServiceRegistrationConfig = {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export type InitialAppServiceRegistrationConfig = {
|
||||||
|
id: string
|
||||||
|
as_token: string
|
||||||
|
hs_token: string
|
||||||
|
sender_localpart: string
|
||||||
|
namespaces: {
|
||||||
|
users: {
|
||||||
|
exclusive: boolean
|
||||||
|
regex: string
|
||||||
|
}[]
|
||||||
|
aliases: {
|
||||||
|
exclusive: boolean
|
||||||
|
regex: string
|
||||||
|
}[]
|
||||||
|
}
|
||||||
|
protocols: [string]
|
||||||
|
rate_limited: boolean
|
||||||
|
ooye: {
|
||||||
|
namespace_prefix: string
|
||||||
|
max_file_size: number,
|
||||||
|
content_length_workaround: boolean,
|
||||||
|
invite: string[],
|
||||||
|
include_user_id_in_mxid: boolean
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
export type WebhookCreds = {
|
export type WebhookCreds = {
|
||||||
id: string
|
id: string
|
||||||
token: string
|
token: string
|
||||||
|
|
Loading…
Reference in a new issue