Authentication may or may not now work

This commit is contained in:
Tulir Asokan
2017-11-13 01:19:12 +02:00
parent 9db90d2d5c
commit daeaca8c4f
13 changed files with 1100 additions and 121 deletions

View File

@@ -7,3 +7,6 @@ end_of_line = lf
charset = utf-8
trim_trailing_whitespace = true
insert_final_newline = true
[*.{yaml,yml}]
indent_style = space

View File

@@ -13,55 +13,125 @@
"import"
],
"rules": {
"indent": ["error", "tab", {
"FunctionDeclaration": {
"parameters": 2,
"body": 1
},
"FunctionExpression": {
"parameters": 2,
"body": 1
},
"VariableDeclarator": 2,
"CallExpression": {
"arguments": 2
},
"MemberExpression": "off",
"ImportDeclaration": "first"
}],
"object-curly-newline": ["error", {
"minProperties": 5,
"consistent": true
}],
"one-var": ["error", {
"initialized": "never",
"uninitialized": "always"
}],
"one-var-declaration-per-line": ["error", "initializations"],
"quotes": ["error", "double"],
"semi": ["error", "never"],
"comma-dangle": ["error", "always-multiline"],
"max-len": ["warn", 80],
"camelcase": ["error", {"properties": "always"}],
"space-before-function-paren": ["error", "never"],
"func-style": ["warn", "declaration", {"allowArrowFunctions": true}],
"id-length": ["warn", {"max": 25, "exceptions": ["i", "x", "y", "$"]}],
"indent": [
"error",
"tab",
{
"FunctionDeclaration": {
"parameters": 2,
"body": 1
},
"FunctionExpression": {
"parameters": 2,
"body": 1
},
"VariableDeclarator": 2,
"CallExpression": {
"arguments": 2
},
"MemberExpression": "off",
"ImportDeclaration": "first"
}
],
"object-curly-newline": [
"error",
{
"minProperties": 5,
"consistent": true
}
],
"one-var": [
"error",
{
"initialized": "never",
"uninitialized": "always"
}
],
"one-var-declaration-per-line": [
"error",
"initializations"
],
"quotes": [
"error",
"double"
],
"semi": [
"error",
"never"
],
"comma-dangle": [
"error",
"always-multiline"
],
"max-len": [
"warn",
80
],
"camelcase": [
"error",
{
"properties": "always"
}
],
"space-before-function-paren": [
"error",
"never"
],
"func-style": [
"warn",
"declaration",
{
"allowArrowFunctions": true
}
],
"id-length": [
"warn",
{
"max": 25,
"exceptions": [
"i",
"x",
"y",
"$"
]
}
],
"import/no-nodejs-modules": "error",
"import/order": ["warn", {
"groups": ["builtin", "external", "internal", "parent", "sibling",
"index"],
"newlines-between": "never"
}],
"arrow-body-style": ["error", "as-needed"],
"complexity": ["warn", 11],
"new-cap": ["warn", {
"newIsCap": true,
"capIsNew": true
}],
"no-empty": ["error", {
"allowEmptyCatch": true
}],
"import/order": [
"warn",
{
"groups": [
"builtin",
"external",
"internal",
"parent",
"sibling",
"index"
],
"newlines-between": "never"
}
],
"arrow-body-style": [
"error",
"as-needed"
],
"complexity": [
"warn",
11
],
"new-cap": [
"warn",
{
"newIsCap": true,
"capIsNew": true
}
],
"no-empty": [
"error",
{
"allowEmptyCatch": true
}
],
"function-paren-newline": "off",
"no-labels": "off",
"no-control-regex": "off",

3
.gitignore vendored
View File

@@ -1,2 +1,5 @@
node_modules/
.idea/
config.yaml
registration.yaml
*.db

View File

@@ -1,4 +1,12 @@
# mautrix-telegram
**Not yet functional.**
A Matrix-Telegram puppeting bridge.
Not yet functional.
## Usage
1. Create a copy of `example-config.yaml` and fill out the fields.
2. Generate the appservice registration with `./mautrix-telegram -g`.
You can use the `-c` and `-r` flags to change the location of the config and registration files.
They default to `config.yaml` and `registration.yaml` respectively.
3. Run the bridge `./mautrix-telegram`. You can also use forever: `forever start mautrix-telegram`.
4. Invite the appservice bot to a private room and view the commands with `!help`.

40
example-config.yaml Normal file
View File

@@ -0,0 +1,40 @@
# Homeserver details
homeserver:
address: https://matrix.org
domain: matrix.org
# Application service host/registration related details
appservice:
# The protocol the homeserver should use when connecting to the appservice.
# Usually "http" or "https".
protocol: http
hostname: localhost
port: 8080
id: telegram
# Path to the registration file. This is automatically updated when generating a registration.
registration: ./registration.yaml
# Bridge config
bridge:
# ${ID} is replaced with the user ID of the Telegram user.
username_template: "telegram_${ID}"
bot_username: telegrambot
# The displayname to set to the bot automatically.
bot_displayname: Telegram Bridge
command_prefix: "!tg"
# Whitelist of user IDs that are allowed to use this bridge. Leave empty to disable.
# You can enter a domain without the localpart to allow all users from that homeserver to use the bridge.
whitelist:
- "internal-hs.example.com"
- "@user:public.example.com"
# Telegram app config. Generate your own keys at https://my.telegram.org/apps
telegram:
server_config:
dev: false
api_config:
api_id: 12345
api_hash: tjyd5yge35lbodk1xwzw2jstp90k55qz

1
mautrix-telegram Symbolic link
View File

@@ -0,0 +1 @@
src/index.js

433
package-lock.json generated
View File

@@ -9,6 +9,19 @@
"resolved": "https://registry.npmjs.org/@goodmind/node-cryptojs-aes/-/node-cryptojs-aes-0.5.0.tgz",
"integrity": "sha1-hNJ9Lsdavw2u05IYHRwgUs4EbPI="
},
"@most/multicast": {
"version": "1.3.0",
"resolved": "https://registry.npmjs.org/@most/multicast/-/multicast-1.3.0.tgz",
"integrity": "sha512-DWH8AShgp5bXn+auGzf5tzPxvpmEvQJd0CNsApOci1LDF4eAEcnw4HQOr2Jaa+L92NbDYFKBSXxll+i7r1ikvw==",
"requires": {
"@most/prelude": "1.6.4"
}
},
"@most/prelude": {
"version": "1.6.4",
"resolved": "https://registry.npmjs.org/@most/prelude/-/prelude-1.6.4.tgz",
"integrity": "sha512-RsT1xRIEc+rCCTZPL3v/tAC+dX1qt1q00ZofEtCJEMEsVg7zT+WLXiVQdhcRqqh4baQTYmDPArXrQWyd7GkqAA=="
},
"Base64": {
"version": "0.2.1",
"resolved": "https://registry.npmjs.org/Base64/-/Base64-0.2.1.tgz",
@@ -103,6 +116,11 @@
"integrity": "sha1-tDLdM1i2NM914eRmQ2gkBTPB3b4=",
"dev": true
},
"apropos": {
"version": "0.6.2",
"resolved": "https://registry.npmjs.org/apropos/-/apropos-0.6.2.tgz",
"integrity": "sha512-iz4Yk3iNe46RofpRq6vrAb+M66cwsnRLqkJHHNDxHsAl7ND4a7QCIx38Z0gd4LxOX/R8NOAcRh7VmOGTkYWU3g=="
},
"argparse": {
"version": "1.0.9",
"resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.9.tgz",
@@ -111,6 +129,11 @@
"sprintf-js": "1.0.3"
}
},
"array-flatten": {
"version": "2.1.1",
"resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-2.1.1.tgz",
"integrity": "sha1-Qmu52oQJDBg42BLIFQryCoMx4pY="
},
"array-union": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/array-union/-/array-union-1.0.2.tgz",
@@ -266,11 +289,6 @@
"tweetnacl": "0.14.5"
}
},
"big.js": {
"version": "3.2.0",
"resolved": "https://registry.npmjs.org/big.js/-/big.js-3.2.0.tgz",
"integrity": "sha512-+hN/Zh2D08Mx65pZ/4g5bsmNiZUuChDiQfTUQ7qJr4/kuopCr88xZsAXv6mBoZEsUI4OuGHlX59qE94K2mMW8Q=="
},
"binary-search-tree": {
"version": "0.2.5",
"resolved": "https://registry.npmjs.org/binary-search-tree/-/binary-search-tree-0.2.5.tgz",
@@ -584,7 +602,6 @@
"version": "2.3.0",
"resolved": "https://registry.npmjs.org/chalk/-/chalk-2.3.0.tgz",
"integrity": "sha512-Az5zJR2CBujap2rqXGaJKaPHyJ0IrUimvYNX+ncCy8PJP4ltOGTrHUIo097ZaL2zMeKYpiCdqDvS6zdrTFok3Q==",
"dev": true,
"requires": {
"ansi-styles": "3.2.0",
"escape-string-regexp": "1.0.5",
@@ -595,7 +612,6 @@
"version": "3.2.0",
"resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.0.tgz",
"integrity": "sha512-NnSOmMEYtVR2JVMIGTzynRkkaxtiq1xnFBcdQD/DnNCYPoEPsVJhM98BDyaoNOQIi7p4okdi3E27eN7GQbsUug==",
"dev": true,
"requires": {
"color-convert": "1.9.1"
}
@@ -604,7 +620,6 @@
"version": "4.5.0",
"resolved": "https://registry.npmjs.org/supports-color/-/supports-color-4.5.0.tgz",
"integrity": "sha1-vnoN5ITexcXN34s9WRJQRJEvY1s=",
"dev": true,
"requires": {
"has-flag": "2.0.0"
}
@@ -650,7 +665,6 @@
"version": "1.9.1",
"resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.1.tgz",
"integrity": "sha512-mjGanIiwQJskCC18rPR6OmrZ6fm2Lc7PeGFYwCmy5J34wC6F1PzdGL6xeMfmgicfYcNLGuVFA3WzXtIDCQSZxQ==",
"dev": true,
"requires": {
"color-name": "1.1.3"
}
@@ -658,8 +672,12 @@
"color-name": {
"version": "1.1.3",
"resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz",
"integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=",
"dev": true
"integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU="
},
"colors": {
"version": "1.1.2",
"resolved": "https://registry.npmjs.org/colors/-/colors-1.1.2.tgz",
"integrity": "sha1-FopHAXVran9RoSzgyXv6KMCE7WM="
},
"combine-source-map": {
"version": "0.6.1",
@@ -680,6 +698,11 @@
"delayed-stream": "0.0.5"
}
},
"commander": {
"version": "2.11.0",
"resolved": "https://registry.npmjs.org/commander/-/commander-2.11.0.tgz",
"integrity": "sha512-b0553uYA5YAEGgyYIGYROzKQ7X5RAqedkfjiZxwi0kL1g3bOaBNNZfYkzt/CL0umgD5wc9Jec2FbB98CjkMRvQ=="
},
"commondir": {
"version": "0.0.1",
"resolved": "https://registry.npmjs.org/commondir/-/commondir-0.0.1.tgz",
@@ -713,6 +736,15 @@
}
}
},
"concurrify": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/concurrify/-/concurrify-1.0.1.tgz",
"integrity": "sha1-H+vktGFdSobuKTo5cT/61f65aB4=",
"requires": {
"sanctuary-type-classes": "6.1.0",
"sanctuary-type-identifiers": "2.0.1"
}
},
"console-browserify": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/console-browserify/-/console-browserify-1.1.0.tgz",
@@ -842,6 +874,14 @@
"resolved": "https://registry.npmjs.org/ctype/-/ctype-0.5.3.tgz",
"integrity": "sha1-gsGMJGH3QRTvFsE1IkrQuRRMoS8="
},
"d": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/d/-/d-1.0.0.tgz",
"integrity": "sha1-dUu1v+VUUdpppYuU1F9MWwRi1Y8=",
"requires": {
"es5-ext": "0.10.35"
}
},
"dashdash": {
"version": "1.14.1",
"resolved": "https://registry.npmjs.org/dashdash/-/dashdash-1.14.1.tgz",
@@ -901,6 +941,11 @@
"resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-0.0.5.tgz",
"integrity": "sha1-1LH0OpPoKW3+AmlPRoC8N6MTxz8="
},
"denque": {
"version": "1.2.2",
"resolved": "https://registry.npmjs.org/denque/-/denque-1.2.2.tgz",
"integrity": "sha512-x92Ql74lcTbGylXILO9Xf9S0cMpEPP04zVp2bB9e2C7G/n/Q1SgLl78RaSYEPSgpDX9uLgQXCEGAS5BI5dP3yA=="
},
"depd": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/depd/-/depd-1.0.1.tgz",
@@ -1027,11 +1072,6 @@
"minimalistic-crypto-utils": "1.0.1"
}
},
"emojis-list": {
"version": "2.1.0",
"resolved": "https://registry.npmjs.org/emojis-list/-/emojis-list-2.1.0.tgz",
"integrity": "sha1-TapNnbAPmBmIDHn6RXrlsJof04k="
},
"error-ex": {
"version": "1.3.1",
"resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.1.tgz",
@@ -1058,6 +1098,45 @@
}
}
},
"es5-ext": {
"version": "0.10.35",
"resolved": "https://registry.npmjs.org/es5-ext/-/es5-ext-0.10.35.tgz",
"integrity": "sha1-GO6FjOajxFx9eekcFfzKnsVoSU8=",
"requires": {
"es6-iterator": "2.0.3",
"es6-symbol": "3.1.1"
}
},
"es6-iterator": {
"version": "2.0.3",
"resolved": "https://registry.npmjs.org/es6-iterator/-/es6-iterator-2.0.3.tgz",
"integrity": "sha1-p96IkUGgWpSwhUQDstCg+/qY87c=",
"requires": {
"d": "1.0.0",
"es5-ext": "0.10.35",
"es6-symbol": "3.1.1"
}
},
"es6-symbol": {
"version": "3.1.1",
"resolved": "https://registry.npmjs.org/es6-symbol/-/es6-symbol-3.1.1.tgz",
"integrity": "sha1-vwDvT9q2uhtG7Le2KbTH7VcVzHc=",
"requires": {
"d": "1.0.0",
"es5-ext": "0.10.35"
}
},
"es6-weak-map": {
"version": "2.0.2",
"resolved": "https://registry.npmjs.org/es6-weak-map/-/es6-weak-map-2.0.2.tgz",
"integrity": "sha1-XjqzIlH/0VOKH45f+hNXdy+S2W8=",
"requires": {
"d": "1.0.0",
"es5-ext": "0.10.35",
"es6-iterator": "2.0.3",
"es6-symbol": "3.1.1"
}
},
"escape-html": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.1.tgz",
@@ -1066,8 +1145,7 @@
"escape-string-regexp": {
"version": "1.0.5",
"resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz",
"integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=",
"dev": true
"integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ="
},
"eslint": {
"version": "4.11.0",
@@ -1346,6 +1424,15 @@
"crc": "3.2.1"
}
},
"event-emitter": {
"version": "0.3.5",
"resolved": "https://registry.npmjs.org/event-emitter/-/event-emitter-0.3.5.tgz",
"integrity": "sha1-34xp7vFkeSPHFXuc6DhAYQsCzDk=",
"requires": {
"d": "1.0.0",
"es5-ext": "0.10.35"
}
},
"eventemitter2": {
"version": "4.1.2",
"resolved": "https://registry.npmjs.org/eventemitter2/-/eventemitter2-4.1.2.tgz",
@@ -1540,6 +1627,23 @@
"write": "0.2.1"
}
},
"fluture": {
"version": "7.2.2",
"resolved": "https://registry.npmjs.org/fluture/-/fluture-7.2.2.tgz",
"integrity": "sha512-V9eRvHDUEvS/jkVNbexi4tzAe+2KLUuzYpSajOTY8JhTBRrsGoSbJJVzengcFWqU8TTsAmEHa6H94QaPJYiF1w==",
"requires": {
"concurrify": "1.0.1",
"denque": "1.2.2",
"inspect-f": "1.2.1",
"sanctuary-type-classes": "6.1.0",
"sanctuary-type-identifiers": "2.0.1"
}
},
"folktale": {
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/folktale/-/folktale-2.0.1.tgz",
"integrity": "sha512-3kDSWVkSlErHIt/dC73vu+5zRqbW1mlnL46s2QfYN7Ps0JcS9MVtuLCrDQOBa7sanA+d9Fd8F+bn0VcyNe68Jw=="
},
"follow-redirects": {
"version": "1.2.5",
"resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.2.5.tgz",
@@ -1593,11 +1697,20 @@
"resolved": "https://registry.npmjs.org/fresh/-/fresh-0.2.4.tgz",
"integrity": "sha1-NYJJkgbJcjcUGQ7ddLRgT+tKYUw="
},
"fs-extra": {
"version": "4.0.2",
"resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-4.0.2.tgz",
"integrity": "sha1-+RcExT0bRh+JNFKwwwfZmXZHq2s=",
"requires": {
"graceful-fs": "4.1.11",
"jsonfile": "4.0.0",
"universalify": "0.1.1"
}
},
"fs.realpath": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz",
"integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=",
"dev": true
"integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8="
},
"function-bind": {
"version": "1.1.1",
@@ -1684,8 +1797,7 @@
"graceful-fs": {
"version": "4.1.11",
"resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.1.11.tgz",
"integrity": "sha1-Dovf5NHduIVNZOBOp8AOKgJuVlg=",
"dev": true
"integrity": "sha1-Dovf5NHduIVNZOBOp8AOKgJuVlg="
},
"har-schema": {
"version": "2.0.0",
@@ -1721,8 +1833,7 @@
"has-flag": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/has-flag/-/has-flag-2.0.0.tgz",
"integrity": "sha1-6CB68cx7MNRGzHC3NLXovhj4jVE=",
"dev": true
"integrity": "sha1-6CB68cx7MNRGzHC3NLXovhj4jVE="
},
"hash-base": {
"version": "2.0.2",
@@ -1913,6 +2024,11 @@
"xtend": "4.0.1"
}
},
"inspect-f": {
"version": "1.2.1",
"resolved": "https://registry.npmjs.org/inspect-f/-/inspect-f-1.2.1.tgz",
"integrity": "sha1-EXVztd9XpQneb+QBEx1Ca6wVkrU="
},
"ipaddr.js": {
"version": "1.0.5",
"resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.0.5.tgz",
@@ -1971,8 +2087,7 @@
"is-promise": {
"version": "2.1.0",
"resolved": "https://registry.npmjs.org/is-promise/-/is-promise-2.1.0.tgz",
"integrity": "sha1-eaKp7OfwlugPNtKy87wWwf9L8/o=",
"dev": true
"integrity": "sha1-eaKp7OfwlugPNtKy87wWwf9L8/o="
},
"is-resolvable": {
"version": "1.0.0",
@@ -2015,8 +2130,7 @@
"js-tokens": {
"version": "3.0.2",
"resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-3.0.2.tgz",
"integrity": "sha1-mGbfOVECEw449/mWvOtlRDIJwls=",
"dev": true
"integrity": "sha1-mGbfOVECEw449/mWvOtlRDIJwls="
},
"js-yaml": {
"version": "3.10.0",
@@ -2068,10 +2182,13 @@
"resolved": "https://registry.npmjs.org/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz",
"integrity": "sha1-Epai1Y/UXxmg9s4B1lcB4sc1tus="
},
"json5": {
"version": "0.5.1",
"resolved": "https://registry.npmjs.org/json5/-/json5-0.5.1.tgz",
"integrity": "sha1-Hq3nrMASA0rYTiOWdn6tn6VJWCE="
"jsonfile": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-4.0.0.tgz",
"integrity": "sha1-h3Gq4HmbZAdrdmQPygWPnBDjPss=",
"requires": {
"graceful-fs": "4.1.11"
}
},
"jsonify": {
"version": "0.0.0",
@@ -2177,16 +2294,6 @@
"strip-bom": "3.0.0"
}
},
"loader-utils": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-1.1.0.tgz",
"integrity": "sha1-yYrvSIvM7aL/teLeZG1qdUQp9c0=",
"requires": {
"big.js": "3.2.0",
"emojis-list": "2.1.0",
"json5": "0.5.1"
}
},
"localforage": {
"version": "1.5.3",
"resolved": "https://registry.npmjs.org/localforage/-/localforage-1.5.3.tgz",
@@ -2216,8 +2323,12 @@
"lodash": {
"version": "4.17.4",
"resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.4.tgz",
"integrity": "sha1-eCA6TRwyiuHYbcpkYONptX9AVa4=",
"dev": true
"integrity": "sha1-eCA6TRwyiuHYbcpkYONptX9AVa4="
},
"lodash-es": {
"version": "4.17.4",
"resolved": "https://registry.npmjs.org/lodash-es/-/lodash-es-4.17.4.tgz",
"integrity": "sha1-3MHXVS4VCgZABzupyzHXDwMpUOc="
},
"lodash.cond": {
"version": "4.5.2",
@@ -2230,6 +2341,14 @@
"resolved": "https://registry.npmjs.org/lodash.memoize/-/lodash.memoize-3.0.4.tgz",
"integrity": "sha1-LcvSwofLwKVcxCMovQxzYVDVPj8="
},
"loose-envify": {
"version": "1.3.1",
"resolved": "https://registry.npmjs.org/loose-envify/-/loose-envify-1.3.1.tgz",
"integrity": "sha1-0aitM/qc4OcT1l/dCsi3SNR4yEg=",
"requires": {
"js-tokens": "3.0.2"
}
},
"lru-cache": {
"version": "4.1.1",
"resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-4.1.1.tgz",
@@ -2240,6 +2359,14 @@
"yallist": "2.1.2"
}
},
"lru-queue": {
"version": "0.1.0",
"resolved": "https://registry.npmjs.org/lru-queue/-/lru-queue-0.1.0.tgz",
"integrity": "sha1-Jzi9nw089PhEkMVzbEhpmsYyzaM=",
"requires": {
"es5-ext": "0.10.35"
}
},
"matrix-appservice": {
"version": "0.3.4",
"resolved": "https://registry.npmjs.org/matrix-appservice/-/matrix-appservice-0.3.4.tgz",
@@ -2369,6 +2496,21 @@
"resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz",
"integrity": "sha1-hxDXrwqmJvj/+hzgAWhUUmMlV0g="
},
"memoizee": {
"version": "0.4.11",
"resolved": "https://registry.npmjs.org/memoizee/-/memoizee-0.4.11.tgz",
"integrity": "sha1-vemBdmPJ5A/bKk6hw2cpYIeujI8=",
"requires": {
"d": "1.0.0",
"es5-ext": "0.10.35",
"es6-weak-map": "2.0.2",
"event-emitter": "0.3.5",
"is-promise": "2.1.0",
"lru-queue": "0.1.0",
"next-tick": "1.0.0",
"timers-ext": "0.1.2"
}
},
"merge-descriptors": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-1.0.0.tgz",
@@ -2510,11 +2652,64 @@
}
}
},
"most": {
"version": "1.7.2",
"resolved": "https://registry.npmjs.org/most/-/most-1.7.2.tgz",
"integrity": "sha512-jDSzUa7HPT79RqLEdrBnYpGZ5DXx8SSDYkS7W6ErBUgU0ewaNDLIdqLJ6GlzXK90eCaDzXm0B1C0KmfTT0XdZQ==",
"requires": {
"@most/multicast": "1.3.0",
"@most/prelude": "1.6.4",
"symbol-observable": "1.0.4"
}
},
"most-subject": {
"version": "5.3.0",
"resolved": "https://registry.npmjs.org/most-subject/-/most-subject-5.3.0.tgz",
"integrity": "sha1-Om4+/UNvqTvYszwqI5yQiCMKYQI=",
"requires": {
"@most/multicast": "1.3.0",
"@most/prelude": "1.6.4",
"most": "1.7.2"
}
},
"ms": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz",
"integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g="
},
"mtproto-logger": {
"version": "0.1.9",
"resolved": "https://registry.npmjs.org/mtproto-logger/-/mtproto-logger-0.1.9.tgz",
"integrity": "sha512-YohXpOVXQuc6DMASbyvLrGevhBZLATh371d3LJaqyuFjcY73C+dpn2tyApgJnJN1mraPEPzPi60BiRONLvZa7g==",
"requires": {
"array-flatten": "2.1.1",
"chalk": "2.3.0",
"debug": "2.6.9",
"eventemitter2": "4.1.2",
"most": "1.7.2",
"mtproto-shared": "0.1.8"
}
},
"mtproto-shared": {
"version": "0.1.8",
"resolved": "https://registry.npmjs.org/mtproto-shared/-/mtproto-shared-0.1.8.tgz",
"integrity": "sha512-dyr4azn8JW3KWS7IJa8dEgIZtpWsFDdYNYBK6WL4u+jRSWmA2MSycIiHLDHYbAbM+7akn5Xi3l/RsDAYGUqtgg==",
"requires": {
"bluebird": "3.5.1",
"memoizee": "0.4.11"
}
},
"mtproto-storage-fs": {
"version": "0.3.1",
"resolved": "https://registry.npmjs.org/mtproto-storage-fs/-/mtproto-storage-fs-0.3.1.tgz",
"integrity": "sha512-QcsQf359e/8LGa9+6LsrA5IESBSZPw+1K0iNH1p269AmLeEOKx+dF7lcbtE/L0ydeyjqbYVPZZLsOeGUE0Lkjg==",
"requires": {
"bluebird": "3.5.1",
"fs-extra": "4.0.2",
"mtproto-logger": "0.1.9",
"mtproto-shared": "0.1.8"
}
},
"mute-stream": {
"version": "0.0.7",
"resolved": "https://registry.npmjs.org/mute-stream/-/mute-stream-0.0.7.tgz",
@@ -2551,6 +2746,11 @@
"resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.5.3.tgz",
"integrity": "sha1-Jp1cR2gQ7JLtvntsLygxY4T5p+g="
},
"next-tick": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/next-tick/-/next-tick-1.0.0.tgz",
"integrity": "sha1-yobR/ogoFpsBICCOPchCS524NCw="
},
"node-uuid": {
"version": "1.4.8",
"resolved": "https://registry.npmjs.org/node-uuid/-/node-uuid-1.4.8.tgz",
@@ -2718,8 +2918,7 @@
"path-is-absolute": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz",
"integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=",
"dev": true
"integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18="
},
"path-is-inside": {
"version": "1.0.2",
@@ -2885,9 +3084,9 @@
"integrity": "sha1-nsYfeQSYdXB9aUFFlv2Qek1xHnM="
},
"ramda": {
"version": "0.23.0",
"resolved": "https://registry.npmjs.org/ramda/-/ramda-0.23.0.tgz",
"integrity": "sha1-zNE//3NJepOXTj6GMnv9h71ujis="
"version": "0.24.1",
"resolved": "https://registry.npmjs.org/ramda/-/ramda-0.24.1.tgz",
"integrity": "sha1-w7d1UZfzW43DUCIoJixMkd22uFc="
},
"randombytes": {
"version": "2.0.5",
@@ -3023,6 +3222,30 @@
}
}
},
"redux": {
"version": "3.7.2",
"resolved": "https://registry.npmjs.org/redux/-/redux-3.7.2.tgz",
"integrity": "sha512-pNqnf9q1hI5HHZRBkj3bAngGZW/JMCmexDlOxw4XagXY2o1327nHH54LoTjiPJ0gizoqPDRqWyX/00g0hD6w+A==",
"requires": {
"lodash": "4.17.4",
"lodash-es": "4.17.4",
"loose-envify": "1.3.1",
"symbol-observable": "1.0.4"
}
},
"redux-act": {
"version": "1.5.0",
"resolved": "https://registry.npmjs.org/redux-act/-/redux-act-1.5.0.tgz",
"integrity": "sha512-DTTYHDJjukWwHoR9B+j4ZEhQVoQ+4OOrluEjFl7ddzVcrzNFHRSoxSTHzGS82QLJ3kshg/Dsr/HXitBD5kn9Cw=="
},
"redux-most": {
"version": "0.6.2",
"resolved": "https://registry.npmjs.org/redux-most/-/redux-most-0.6.2.tgz",
"integrity": "sha1-BFHaHWH3aqv/mtw4DTINPmc7FoY=",
"requires": {
"most-subject": "5.3.0"
}
},
"request": {
"version": "2.83.0",
"resolved": "https://registry.npmjs.org/request/-/request-2.83.0.tgz",
@@ -3291,14 +3514,26 @@
"resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.1.tgz",
"integrity": "sha512-kKvNJn6Mm93gAczWVJg7wH+wGYWNrDHdWvpUmHyEsgCtIwwo3bqPtV4tR5tuPaUhTOo/kvhVwd8XwwOllGYkbg=="
},
"schema-utils": {
"version": "0.3.0",
"resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-0.3.0.tgz",
"integrity": "sha1-9YdyIs4+kx7a4DnxfrNxbnE3+M8=",
"sanctuary-type-classes": {
"version": "6.1.0",
"resolved": "https://registry.npmjs.org/sanctuary-type-classes/-/sanctuary-type-classes-6.1.0.tgz",
"integrity": "sha1-a9ZwRDWMhEDVYebiVWq4jdjNgAE=",
"requires": {
"ajv": "5.3.0"
"sanctuary-type-identifiers": "1.0.0"
},
"dependencies": {
"sanctuary-type-identifiers": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/sanctuary-type-identifiers/-/sanctuary-type-identifiers-1.0.0.tgz",
"integrity": "sha1-6PNZ8AbLXmJM+4RkYD/BFGCL3p8="
}
}
},
"sanctuary-type-identifiers": {
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/sanctuary-type-identifiers/-/sanctuary-type-identifiers-2.0.1.tgz",
"integrity": "sha1-/FJM9t2Szr/LsN2VCe/xkxWaIO0="
},
"semver": {
"version": "5.4.1",
"resolved": "https://registry.npmjs.org/semver/-/semver-5.4.1.tgz",
@@ -3593,6 +3828,11 @@
"integrity": "sha1-U10EXOa2Nj+kARcIRimZXp3zJMc=",
"dev": true
},
"symbol-observable": {
"version": "1.0.4",
"resolved": "https://registry.npmjs.org/symbol-observable/-/symbol-observable-1.0.4.tgz",
"integrity": "sha1-Kb9hXUqnEhvdiYsi1LP5vE4qoD0="
},
"syntax-error": {
"version": "1.3.0",
"resolved": "https://registry.npmjs.org/syntax-error/-/syntax-error-1.3.0.tgz",
@@ -3616,23 +3856,41 @@
}
},
"telegram-mtproto": {
"version": "2.2.8",
"resolved": "https://registry.npmjs.org/telegram-mtproto/-/telegram-mtproto-2.2.8.tgz",
"integrity": "sha1-HmVsSjk2omxiTgkD6IPAC7HnPhU=",
"version": "3.2.11",
"resolved": "https://registry.npmjs.org/telegram-mtproto/-/telegram-mtproto-3.2.11.tgz",
"integrity": "sha512-WZPC5TfZCtvBc+TQd6jX1WzcMEBn7w4EIKanusBP1nicFn6hIiUK2XXcmVnt+ObA6Aq1+GZht11qgTZb8JSPOQ==",
"requires": {
"@goodmind/node-cryptojs-aes": "0.5.0",
"@most/prelude": "1.6.4",
"ajv": "5.3.0",
"ajv-keywords": "2.1.1",
"apropos": "0.6.2",
"axios": "0.16.2",
"bluebird": "3.5.1",
"debug": "2.6.9",
"detect-node": "2.0.3",
"eventemitter2": "4.1.2",
"fluture": "7.2.2",
"folktale": "2.0.1",
"most": "1.7.2",
"most-subject": "5.3.0",
"mtproto-logger": "0.1.9",
"mtproto-shared": "0.1.8",
"mtproto-storage-fs": "0.3.1",
"pako": "1.0.6",
"ramda": "0.23.0",
"ramda": "0.24.1",
"randombytes": "2.0.5",
"redux": "3.7.2",
"redux-act": "1.5.0",
"redux-most": "0.6.2",
"rusha": "0.8.7",
"worker-loader": "0.8.1"
"uuid": "3.1.0"
},
"dependencies": {
"uuid": {
"version": "3.1.0",
"resolved": "https://registry.npmjs.org/uuid/-/uuid-3.1.0.tgz",
"integrity": "sha512-DIWtzUkw04M4k3bf1IcpS2tngXEL26YUD2M0tMDUpnUrz2hgzUBlD55a4FjdLGPvfHxS6uluGWvaVEqgBcVa+g=="
}
}
},
"text-table": {
@@ -3676,6 +3934,15 @@
"process": "0.11.10"
}
},
"timers-ext": {
"version": "0.1.2",
"resolved": "https://registry.npmjs.org/timers-ext/-/timers-ext-0.1.2.tgz",
"integrity": "sha1-YcxHp2wavTGV8UUn+XjViulMUgQ=",
"requires": {
"es5-ext": "0.10.35",
"next-tick": "1.0.0"
}
},
"tmp": {
"version": "0.0.33",
"resolved": "https://registry.npmjs.org/tmp/-/tmp-0.0.33.tgz",
@@ -3748,6 +4015,11 @@
"resolved": "https://registry.npmjs.org/underscore/-/underscore-1.4.4.tgz",
"integrity": "sha1-YaajIBBiKvoHljvzJSA88SI51gQ="
},
"universalify": {
"version": "0.1.1",
"resolved": "https://registry.npmjs.org/universalify/-/universalify-0.1.1.tgz",
"integrity": "sha1-+nG63UQ3r0wUiEHjs7Fl+enlkLc="
},
"unreachable-branch-transform": {
"version": "0.3.0",
"resolved": "https://registry.npmjs.org/unreachable-branch-transform/-/unreachable-branch-transform-0.3.0.tgz",
@@ -3871,15 +4143,6 @@
"integrity": "sha1-J1hIEIkUVqQXHI0CJkQa3pDLyus=",
"dev": true
},
"worker-loader": {
"version": "0.8.1",
"resolved": "https://registry.npmjs.org/worker-loader/-/worker-loader-0.8.1.tgz",
"integrity": "sha1-6OmVMx6jTfW/aCloJL+38K1XjUM=",
"requires": {
"loader-utils": "1.1.0",
"schema-utils": "0.3.0"
}
},
"wrappy": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz",
@@ -3904,6 +4167,38 @@
"resolved": "https://registry.npmjs.org/yallist/-/yallist-2.1.2.tgz",
"integrity": "sha1-HBH5IY8HYImkfdUS+TxmmaaoHVI=",
"dev": true
},
"yamljs": {
"version": "0.3.0",
"resolved": "https://registry.npmjs.org/yamljs/-/yamljs-0.3.0.tgz",
"integrity": "sha512-C/FsVVhht4iPQYXOInoxUM/1ELSf9EsgKH34FofQOp6hwCPrW4vG4w5++TED3xRUo8gD7l0P1J1dLlDYzODsTQ==",
"requires": {
"argparse": "1.0.9",
"glob": "7.1.2"
},
"dependencies": {
"glob": {
"version": "7.1.2",
"resolved": "https://registry.npmjs.org/glob/-/glob-7.1.2.tgz",
"integrity": "sha512-MJTUg1kjuLeQCJ+ccE4Vpa6kKVXkPYJ2mOCQyUuKLcLQsdrMCpBPUi8qVE6+YuaJkozeA9NusTAw3hLr8Xe5EQ==",
"requires": {
"fs.realpath": "1.0.0",
"inflight": "1.0.6",
"inherits": "2.0.3",
"minimatch": "3.0.4",
"once": "1.4.0",
"path-is-absolute": "1.0.1"
}
},
"minimatch": {
"version": "3.0.4",
"resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz",
"integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==",
"requires": {
"brace-expansion": "1.1.8"
}
}
}
}
}
}

View File

@@ -4,15 +4,18 @@
"description": "A Matrix-Telegram puppeting bridge",
"author": "Tulir Asokan <tulir@maunium.net>",
"license": "GPL-3.0",
"main": "index.js",
"main": "src/index.js",
"repository": {
"type": "git",
"url": "https://github.com/tulir/mautrix-telegram.git"
},
"dependencies": {
"telegram-mtproto": "2.x.x",
"telegram-mtproto": "3.2.x",
"matrix-js-sdk": "0.x.x",
"matrix-appservice-bridge": "1.x.x"
"matrix-appservice-bridge": "1.x.x",
"commander": "2.11.x",
"yamljs": "0.3.x",
"colors": "1.1.x"
},
"devDependencies": {
"eslint": "4.11.x",

151
src/app.js Normal file
View File

@@ -0,0 +1,151 @@
// mautrix-telegram - A Matrix-Telegram puppeting bridge
// Copyright (C) 2017 Tulir Asokan
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
const {Bridge} = require("matrix-appservice-bridge")
const commands = require("./commands")
const MatrixUser = require("./matrix-user")
class MautrixTelegram {
constructor(config) {
this.config = config
this.matrixUsersByID = new Map()
this.telegramUsersByID = new Map()
const self = this
this.bridge = new Bridge({
homeserverUrl: config.homeserver.address,
domain: config.homeserver.domain,
registration: config.appservice.registration,
controller: {
onUserQuery(user) {
return {}
},
onEvent(request, context) {
self.handleMatrixEvent(request.getData())
},
},
})
}
run() {
console.log("Appservice listening on port %s", this.config.appservice.port)
this.bridge.run(this.config.appservice.port, {})
//this.botIntent.setDisplayName(this.config.bridge.bot_displayname)
}
get bot() {
return this.bridge.getBot()
}
get botIntent() {
return this.bridge.getIntent()
}
getMatrixUser(id) {
let user = this.matrixUsersByID.get(id)
if (user) {
console.log(id, "found in cache")
return Promise.resolve(user)
}
return this.bridge.getUserStore().select({
type: "matrix",
id,
}).then(entries => {
this.matrixUsersByID.get(id)
if (user) {
console.log(id, "found in cache (after race)")
return Promise.resolve(user)
}
if (entries.length) {
user = MatrixUser.fromEntry(this, entries[0])
console.log(id, "loaded from database")
} else {
user = new MatrixUser(this, id)
console.log(id, "created")
}
this.matrixUsersByID.set(id, user)
return user
})
}
putUser(user) {
const entry = user.toEntry()
return this.bridge.getUserStore().upsert({
type: entry.type,
id: entry.id,
}, entry)
}
handleMatrixEvent(evt) {
const asBotID = this.bridge.getBot().getUserId()
if (evt.type === "m.room.member" && evt.state_key === asBotID) {
if (evt.content.membership === "invite") {
// Accept all invites
this.botIntent.join(evt.room_id)
.catch(err => {
console.warn(`Failed to join room ${evt.room_id}:`, err)
if (e instanceof Error) {
console.warn(e.stack)
}
})
}
return
}
if (evt.sender === asBotID || evt.type !== "m.room.message" || !evt.content) {
// Ignore own messages and non-message events.
return;
}
const cmdprefix = this.config.bridge.command_prefix
if (evt.content.body.startsWith(cmdprefix + " ")) {
this.getMatrixUser(evt.sender).then(user => {
if (!user.whitelisted) {
this.botIntent.sendText(evt.room_id, "You are not authorized to use this bridge.")
return
}
const prefixLength = cmdprefix.length + 1
const args = evt.content.body.substr(prefixLength).split(" ")
const command = args.shift()
commands.run(user, command, args, reply =>
this.botIntent.sendText(
evt.room_id,
reply.replace("$cmdprefix", cmdprefix)))
})
return
}
}
checkWhitelist(userID) {
if (!this.config.bridge.whitelist || this.config.bridge.whitelist.length === 0) {
return true
}
userID = userID.toLowerCase()
const userIDCapture = /\@.+\:(.+)/.exec(userID)
const homeserver = userIDCapture && userIDCapture.length > 1 ? userIDCapture[1] : undefined
for (let whitelisted of this.config.bridge.whitelist) {
whitelisted = whitelisted.toLowerCase()
if (whitelisted === userID || (homeserver && whitelisted === homeserver)) {
return true
}
}
return false
}
}
module.exports = MautrixTelegram

126
src/commands.js Normal file
View File

@@ -0,0 +1,126 @@
// mautrix-telegram - A Matrix-Telegram puppeting bridge
// Copyright (C) 2017 Tulir Asokan
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
const makePasswordHash = require("telegram-mtproto").plugins.makePasswordHash
class Command {
constructor(description, usage, func) {
this.description = description
this.usage = usage
this.func = func
}
run(app, roomID, args) {
this.func(args, message =>
app.botIntent.sendText(roomID, message))
}
}
const commands = {}
function run(sender, command, args, reply) {
if (sender.commandStatus) {
if (command === "cancel") {
sender.commandStatus = undefined
reply(`${sender.commandStatus.action} cancelled.`)
return
}
args.unshift(command)
sender.commandStatus.next(sender, args, reply)
return
}
command = this.commands[command]
if (!command) {
reply("Unknown command. Try \"$cmdprefix help\" for help.")
}
command(sender, args, reply)
}
commands.cancel = () => "Nothing to cancel."
const enterPassword = (sender, args, reply) => {
if (args.length === 0) {
reply("Usage: $cmdprefix <password>")
return
}
const hash = makePasswordHash(sender.commandStatus.salt, args[0])
sender.checkPassword(hash)
.then(() => {
// TODO show who the user logged in as
reply(`Logged in successfully.`)
sender.commandStatus = undefined
}, err => {
reply(`Login failed: ${err}`)
console.log(err)
})
}
const enterCode = (sender, args, reply) => {
if (args.length === 0) {
reply("Usage: $cmdprefix <authentication code>")
return
}
sender.signInToTelegram(args[0])
.then(data => {
if (data.status === "ok") {
// TODO show who the user logged in as
reply(`Logged in successfully.`)
sender.commandStatus = undefined
} else if (data.status === "need-password") {
reply(`You have two-factor authentication enabled. Password hint: ${data.hint} \nEnter your password using "$cmdprefix <password>"`)
sender.commandStatus = {
action: "Two-factor authentication",
next: enterPassword,
salt: data.salt,
}
} else {
reply(`Unexpected sign in response, status=${data.status}`)
}
}, err => {
reply(`Login failed: ${err}`)
console.log(err)
})
}
commands.login = (sender, args, reply) => {
if (args.length === 0) {
reply("Usage: $cmdprefix login <phone number>")
return
}
sender.sendTelegramCode(args[0])
.then(data => {
reply(`Login code sent to ${args[0]}. \nEnter the code using "$cmdprefix <code>"`)
sender.commandStatus = {
action: "Phone code authentication",
next: enterCode,
}
console.log(data)
}, err => {
reply(`Failed to send code: ${err}`)
console.log(err)
})
}
commands.help = (sender, args, reply) => {
reply("Help not yet implemented 3:")
}
module.exports = {
commands,
run,
}

60
src/index.js Executable file
View File

@@ -0,0 +1,60 @@
#!/usr/bin/env node
// mautrix-telegram - A Matrix-Telegram puppeting bridge
// Copyright (C) 2017 Tulir Asokan
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
const {AppServiceRegistration} = require("matrix-appservice-bridge")
const commander = require("commander")
const YAML = require("yamljs")
const fs = require("fs")
const MautrixTelegram = require("./app")
const pkg = require("../package.json")
commander
.version(pkg.version)
.option("-c, --config <path>", "the file to load the config from. defaults to ./config.yaml")
.option("-g, --generate-registration", "generate a registration based on the config")
.option("-r, --registration <path>", "the file to save the registration to. defaults to ./registration.yaml")
.parse(process.argv)
commander.registration = commander.registration || "./registration.yaml"
commander.config = commander.config || "./config.yaml"
const config = YAML.load(commander.config)
if (commander.generateRegistration) {
const registration = {
id: config.appservice.id,
hs_token: AppServiceRegistration.generateToken(),
as_token: AppServiceRegistration.generateToken(),
namespaces: {
users: [{
exclusive: true,
regex: `@${config.bridge.username_template.replace("${ID}", ".+")}:${config.homeserver.domain}`
}],
aliases: [],
rooms: [],
},
url: `${config.appservice.protocol}://${config.appservice.hostname}:${config.appservice.port}`,
sender_localpart: config.bridge.bot_username,
rate_limited: false,
}
fs.writeFileSync(commander.registration, YAML.stringify(registration, 10))
config.appservice.registration = commander.registration
fs.writeFileSync(commander.config, YAML.stringify(config, 10))
return
}
const app = new MautrixTelegram(config)
app.run()

104
src/matrix-user.js Normal file
View File

@@ -0,0 +1,104 @@
// mautrix-telegram - A Matrix-Telegram puppeting bridge
// Copyright (C) 2017 Tulir Asokan
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
const TelegramPuppet = require("./telegram-puppet")
class MatrixUser {
constructor(app, userID) {
this.app = app
this.userID = userID
this.whitelisted = app.checkWhitelist(userID)
this.phoneNumber = undefined
this.phoneCodeHash = undefined
this.commandStatus = undefined
this._telegramPuppet = undefined
}
static fromEntry(app, entry) {
if (entry.type !== "matrix") {
throw new Error("MatrixUser can only be created from entry type \"matrix\"")
}
const user = new MatrixUser(app, entry.id)
user.phoneNumber = entry.data.phone_number
user.phoneCodeHash = entry.data.phone_code_hash
if (entry.data.puppet) {
user.puppetData = entry.data.puppet
user.telegramPuppet
}
return user
}
toEntry() {
if (this.puppet) {
this.puppetData = this.puppet.toSubentry()
}
return {
type: "matrix",
id: this.userID,
data: {
phone_number: this.phoneNumber,
phone_code_hash: this.phoneCodeHash,
puppet: this.puppetData,
},
}
}
get telegramPuppet() {
if (!this._telegramPuppet) {
this._telegramPuppet = TelegramPuppet.fromSubentry(this.app, this, this.puppetData || {})
}
return this._telegramPuppet
}
parseTelegramError(err) {
const message = err.toPrintable ? err.toPrintable() : err.toString()
if (err instanceof Error) {
throw err
}
throw new Error(message)
}
sendTelegramCode(phoneNumber) {
// TODO handle existing login?
return this.telegramPuppet.sendCode(phoneNumber)
.then(result => {
this.phoneNumber = phoneNumber
this.phoneCodeHash = result.phone_code_hash
this.app.putUser(this)
return result
}, err => this.parseTelegramError(err))
}
signInToTelegram(phoneCode) {
if (!this.phoneNumber) throw new Error("Phone number not set")
if (!this.phoneCodeHash) throw new Error("Phone code not sent")
return this.telegramPuppet.signIn(this.phoneNumber, this.phoneCodeHash, phoneCode)
.then(result => {
this.phoneCodeHash = undefined
return this.app.putUser(this).then(() => result)
})
}
checkPassword(password_hash) {
return this.telegramPuppet.checkPassword(password_hash)
.then(() => this.app.putUser(this))
}
}
module.exports = MatrixUser

115
src/telegram-puppet.js Normal file
View File

@@ -0,0 +1,115 @@
// mautrix-telegram - A Matrix-Telegram puppeting bridge
// Copyright (C) 2017 Tulir Asokan
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
const pkg = require("../package.json")
const os = require("os")
const telegram = require("telegram-mtproto")
class TelegramPuppet {
constructor(opts) {
this._client = undefined
this.userID = opts.userID
this.matrixUser = opts.matrixUser
this.data = opts.data
this.app = opts.app
this.serverConfig = Object.assign({}, opts.server_config)
this.api_hash = opts.api_hash
this.api_id = opts.api_id
this.apiConfig = Object.assign({}, {
app_version: pkg.version,
lang_code: "en",
api_id: opts.api_id,
}, opts.api_config)
}
static fromSubentry(app, matrixUser, data) {
const userID = data.user_id
delete data.user_id
return new TelegramPuppet(Object.assign({
userID,
matrixUser,
data,
app,
}, app.config.telegram))
}
toSubentry() {
return Object.assign({
user_id: this.userID
}, this.data)
}
get datacenter() {
return { dcID: 1 }
}
get client() {
if (!this._client) {
this._client = telegram.MTProto({
api: this.apiConfig,
server: this.serverConfig,
})
}
return this._client
}
sendCode(phone_number) {
return this.client("auth.sendCode", {
phone_number,
current_number: true,
api_id: this.api_id,
api_hash: this.api_hash,
})
}
signIn(phone_number, phone_code_hash, phone_code) {
return this.client("auth.signIn", {
phone_number, phone_code, phone_code_hash
})
.then(
result => this.signInComplete(result),
err => {
if (err.type !== "SESSION_PASSWORD_NEEDED") {
throw err
}
this.client("account.getPassword", {}).then(data => {
return {
status: "need-password",
hint: data.hint,
salt: data.current_salt
}
})
})
}
checkPassword(password_hash) {
return this.client("auth.checkPassword", {password_hash})
.then((result) => this.signInComplete(result))
}
signInComplete(data) {
this.userID = data.user.id
return {
status: "ok"
}
}
}
module.exports = TelegramPuppet