Merge branch 'dev' into dev

This commit is contained in:
Krishan 2022-08-15 09:41:00 +05:30 committed by GitHub
commit 192c1bdb63
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
24 changed files with 364 additions and 270 deletions

View file

@ -15,7 +15,7 @@ jobs:
- name: Checkout repository - name: Checkout repository
uses: actions/checkout@v3.0.2 uses: actions/checkout@v3.0.2
- name: Build Docker image - name: Build Docker image
uses: docker/build-push-action@v3.1.0 uses: docker/build-push-action@v3.1.1
with: with:
context: . context: .
push: false push: false

View file

@ -86,7 +86,7 @@ jobs:
with: with:
images: ajbura/cinny images: ajbura/cinny
- name: Build and push Docker image - name: Build and push Docker image
uses: docker/build-push-action@v3.1.0 uses: docker/build-push-action@v3.1.1
with: with:
context: . context: .
platforms: linux/amd64,linux/arm64 platforms: linux/amd64,linux/arm64

BIN
olm.wasm Normal file → Executable file

Binary file not shown.

133
package-lock.json generated
View file

@ -1,18 +1,18 @@
{ {
"name": "cinny", "name": "cinny",
"version": "2.0.4", "version": "2.1.2",
"lockfileVersion": 2, "lockfileVersion": 2,
"requires": true, "requires": true,
"packages": { "packages": {
"": { "": {
"name": "cinny", "name": "cinny",
"version": "2.0.4", "version": "2.1.2",
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
"@alienfast/i18next-loader": "^1.1.4", "@alienfast/i18next-loader": "^1.1.4",
"@fontsource/inter": "^4.5.11", "@fontsource/inter": "^4.5.12",
"@fontsource/roboto": "^4.5.7", "@fontsource/roboto": "^4.5.8",
"@matrix-org/olm": "https://gitlab.matrix.org/api/v4/projects/27/packages/npm/@matrix-org/olm/-/@matrix-org/olm-3.2.8.tgz", "@matrix-org/olm": "https://gitlab.matrix.org/api/v4/projects/27/packages/npm/@matrix-org/olm/-/@matrix-org/olm-3.2.12.tgz",
"@tippyjs/react": "^4.2.6", "@tippyjs/react": "^4.2.6",
"babel-polyfill": "^6.26.0", "babel-polyfill": "^6.26.0",
"blurhash": "^1.1.5", "blurhash": "^1.1.5",
@ -29,7 +29,7 @@
"katex": "^0.16.0", "katex": "^0.16.0",
"linkify-html": "^4.0.0-beta.5", "linkify-html": "^4.0.0-beta.5",
"linkifyjs": "^4.0.0-beta.5", "linkifyjs": "^4.0.0-beta.5",
"matrix-js-sdk": "^18.1.0", "matrix-js-sdk": "^19.2.0",
"micromark": "^3.0.10", "micromark": "^3.0.10",
"micromark-extension-gfm": "^2.0.1", "micromark-extension-gfm": "^2.0.1",
"micromark-extension-math": "^2.0.2", "micromark-extension-math": "^2.0.2",
@ -75,7 +75,7 @@
"html-webpack-plugin": "^5.3.1", "html-webpack-plugin": "^5.3.1",
"mini-css-extract-plugin": "^2.6.1", "mini-css-extract-plugin": "^2.6.1",
"path-browserify": "^1.0.1", "path-browserify": "^1.0.1",
"sass": "^1.54.1", "sass": "^1.54.3",
"sass-loader": "^13.0.2", "sass-loader": "^13.0.2",
"stream-browserify": "^3.0.0", "stream-browserify": "^3.0.0",
"style-loader": "^3.3.1", "style-loader": "^3.3.1",
@ -1897,14 +1897,14 @@
} }
}, },
"node_modules/@fontsource/inter": { "node_modules/@fontsource/inter": {
"version": "4.5.11", "version": "4.5.12",
"resolved": "https://registry.npmjs.org/@fontsource/inter/-/inter-4.5.11.tgz", "resolved": "https://registry.npmjs.org/@fontsource/inter/-/inter-4.5.12.tgz",
"integrity": "sha512-toizzQkfXL8YJcG/f8j3EYXYGQe4OxiDEItThSigvHU+cYNDw8HPp3wLYQX745hddsnHqOGCM4exitFSBOU8+w==" "integrity": "sha512-bGKk4/8tube/nCk8hav0ZDBVbzJzc7m0Vt4xF5p15IN4YImwGdtKG38Oq5bU8xHNS+VfvbFFCepgQNj7Pr/Lvg=="
}, },
"node_modules/@fontsource/roboto": { "node_modules/@fontsource/roboto": {
"version": "4.5.7", "version": "4.5.8",
"resolved": "https://registry.npmjs.org/@fontsource/roboto/-/roboto-4.5.7.tgz", "resolved": "https://registry.npmjs.org/@fontsource/roboto/-/roboto-4.5.8.tgz",
"integrity": "sha512-m57UMER23Mk6Drg9OjtHW1Y+0KPGyZfE5XJoPTOsLARLar6013kJj4X2HICt+iFLJqIgTahA/QAvSn9lwF1EEw==" "integrity": "sha512-CnD7zLItIzt86q4Sj3kZUiLcBk1dSk81qcqgMGaZe7SQ1P8hFNxhMl5AZthK1zrDM5m74VVhaOpuMGIL4gagaA=="
}, },
"node_modules/@humanwhocodes/config-array": { "node_modules/@humanwhocodes/config-array": {
"version": "0.10.4", "version": "0.10.4",
@ -2485,9 +2485,9 @@
"dev": true "dev": true
}, },
"node_modules/@matrix-org/olm": { "node_modules/@matrix-org/olm": {
"version": "3.2.8", "version": "3.2.12",
"resolved": "https://gitlab.matrix.org/api/v4/projects/27/packages/npm/@matrix-org/olm/-/@matrix-org/olm-3.2.8.tgz", "resolved": "https://gitlab.matrix.org/api/v4/projects/27/packages/npm/@matrix-org/olm/-/@matrix-org/olm-3.2.12.tgz",
"integrity": "sha512-yCJzEYY2aG1z+7nxKYZC4DFYwQO/5iG019qgotJhauYJRhEG9gLrKTvXO6lRHS8TjnZzsZFZyO/hQUlI4Dryig==", "integrity": "sha512-muHkYUAXyRDg88YVFlmFY35vgLPovK2YPkuEtBfgnmBcxJvLpV9UMcMMxNkf8opjMV1k/NJ4niFQMzwd4UQOiA==",
"license": "Apache-2.0" "license": "Apache-2.0"
}, },
"node_modules/@nodelib/fs.scandir": { "node_modules/@nodelib/fs.scandir": {
@ -3076,8 +3076,6 @@
"resolved": "https://registry.npmjs.org/ajv/-/ajv-8.9.0.tgz", "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.9.0.tgz",
"integrity": "sha512-qOKJyNj/h+OWx7s5DePL6Zu1KeM9jPZhwBqs+7DzP6bGOvqzVCSf0xueYmVuaC/oQ/VtS2zLMLHdQFbkka+XDQ==", "integrity": "sha512-qOKJyNj/h+OWx7s5DePL6Zu1KeM9jPZhwBqs+7DzP6bGOvqzVCSf0xueYmVuaC/oQ/VtS2zLMLHdQFbkka+XDQ==",
"dev": true, "dev": true,
"optional": true,
"peer": true,
"dependencies": { "dependencies": {
"fast-deep-equal": "^3.1.1", "fast-deep-equal": "^3.1.1",
"json-schema-traverse": "^1.0.0", "json-schema-traverse": "^1.0.0",
@ -3093,9 +3091,7 @@
"version": "1.0.0", "version": "1.0.0",
"resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz",
"integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==", "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==",
"dev": true, "dev": true
"optional": true,
"peer": true
}, },
"node_modules/ajv-keywords": { "node_modules/ajv-keywords": {
"version": "3.5.2", "version": "3.5.2",
@ -3527,12 +3523,9 @@
"integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==" "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw=="
}, },
"node_modules/base-x": { "node_modules/base-x": {
"version": "3.0.9", "version": "4.0.0",
"resolved": "https://registry.npmjs.org/base-x/-/base-x-3.0.9.tgz", "resolved": "https://registry.npmjs.org/base-x/-/base-x-4.0.0.tgz",
"integrity": "sha512-H7JU6iBHTal1gp56aKoaa//YUxEaAOUiydvrV/pILqIHXTtqxSkATOnDA2u+jZ/61sD+L/412+7kzXRtWukhpQ==", "integrity": "sha512-FuwxlW4H5kh37X/oW59pwTzzTKRzfrrQwhmyspRM7swOEZcHtDZSCt45U6oKgtuFE+WYPblePMVIPR4RZrh/hw=="
"dependencies": {
"safe-buffer": "^5.0.1"
}
}, },
"node_modules/base64-js": { "node_modules/base64-js": {
"version": "1.5.1", "version": "1.5.1",
@ -3877,11 +3870,11 @@
} }
}, },
"node_modules/bs58": { "node_modules/bs58": {
"version": "4.0.1", "version": "5.0.0",
"resolved": "https://registry.npmjs.org/bs58/-/bs58-4.0.1.tgz", "resolved": "https://registry.npmjs.org/bs58/-/bs58-5.0.0.tgz",
"integrity": "sha1-vhYedsNU9veIrkBx9j806MTwpCo=", "integrity": "sha512-r+ihvQJvahgYT50JD05dyJNKlmmSlMoOGwn1lCcEzanPglg7TxYjioQUYehQ9mAR/+hOSd2jRc/Z2y5UxBymvQ==",
"dependencies": { "dependencies": {
"base-x": "^3.0.2" "base-x": "^4.0.0"
} }
}, },
"node_modules/buffer": { "node_modules/buffer": {
@ -9291,18 +9284,18 @@
"integrity": "sha512-9jl4wtWanUFSy2sr2lCjErN/oC8KTAtaeaozJtrgot1JiQcEI4Rda9OLgQ7nLKaqb4Z/QUx/fR3XpDzm5Jy1JA==" "integrity": "sha512-9jl4wtWanUFSy2sr2lCjErN/oC8KTAtaeaozJtrgot1JiQcEI4Rda9OLgQ7nLKaqb4Z/QUx/fR3XpDzm5Jy1JA=="
}, },
"node_modules/matrix-js-sdk": { "node_modules/matrix-js-sdk": {
"version": "18.1.0", "version": "19.2.0",
"resolved": "https://registry.npmjs.org/matrix-js-sdk/-/matrix-js-sdk-18.1.0.tgz", "resolved": "https://registry.npmjs.org/matrix-js-sdk/-/matrix-js-sdk-19.2.0.tgz",
"integrity": "sha512-O5D36paIsY7a2M2mOo7KKU7v1Mb3PVkmYKupXYcXd9gB/Ki1K4mds+vSDEhgkKyKwk6MK1AV/vgvp0xJCsttvg==", "integrity": "sha512-alvTasCTCo/XXSIkKEj8xKe1NMsyiVDDVIQdU9ZHI1aePq+DrAcx8CqB7L/dgjk842v+63Eke1f/jZuFWvjn4w==",
"dependencies": { "dependencies": {
"@babel/runtime": "^7.12.5", "@babel/runtime": "^7.12.5",
"another-json": "^0.2.0", "another-json": "^0.2.0",
"browser-request": "^0.3.3", "browser-request": "^0.3.3",
"bs58": "^4.0.1", "bs58": "^5.0.0",
"content-type": "^1.0.4", "content-type": "^1.0.4",
"loglevel": "^1.7.1", "loglevel": "^1.7.1",
"matrix-events-sdk": "^0.0.1-beta.7", "matrix-events-sdk": "^0.0.1-beta.7",
"p-retry": "^4.5.0", "p-retry": "4",
"qs": "^6.9.6", "qs": "^6.9.6",
"request": "^2.88.2", "request": "^2.88.2",
"unhomoglyph": "^1.0.6" "unhomoglyph": "^1.0.6"
@ -12388,9 +12381,9 @@
} }
}, },
"node_modules/sass": { "node_modules/sass": {
"version": "1.54.1", "version": "1.54.3",
"resolved": "https://registry.npmjs.org/sass/-/sass-1.54.1.tgz", "resolved": "https://registry.npmjs.org/sass/-/sass-1.54.3.tgz",
"integrity": "sha512-GHJJr31Me32RjjUBagyzx8tzjKBUcDwo5239XANIRBq0adDu5iIG0aFO0i/TBb/4I9oyxkEv44nq/kL1DxdDhA==", "integrity": "sha512-fLodey5Qd41Pxp/Tk7Al97sViYwF/TazRc5t6E65O7JOk4XF8pzwIW7CvCxYVOfJFFI/1x5+elDyBIixrp+zrw==",
"dev": true, "dev": true,
"dependencies": { "dependencies": {
"chokidar": ">=3.0.0 <4.0.0", "chokidar": ">=3.0.0 <4.0.0",
@ -15985,14 +15978,14 @@
} }
}, },
"@fontsource/inter": { "@fontsource/inter": {
"version": "4.5.11", "version": "4.5.12",
"resolved": "https://registry.npmjs.org/@fontsource/inter/-/inter-4.5.11.tgz", "resolved": "https://registry.npmjs.org/@fontsource/inter/-/inter-4.5.12.tgz",
"integrity": "sha512-toizzQkfXL8YJcG/f8j3EYXYGQe4OxiDEItThSigvHU+cYNDw8HPp3wLYQX745hddsnHqOGCM4exitFSBOU8+w==" "integrity": "sha512-bGKk4/8tube/nCk8hav0ZDBVbzJzc7m0Vt4xF5p15IN4YImwGdtKG38Oq5bU8xHNS+VfvbFFCepgQNj7Pr/Lvg=="
}, },
"@fontsource/roboto": { "@fontsource/roboto": {
"version": "4.5.7", "version": "4.5.8",
"resolved": "https://registry.npmjs.org/@fontsource/roboto/-/roboto-4.5.7.tgz", "resolved": "https://registry.npmjs.org/@fontsource/roboto/-/roboto-4.5.8.tgz",
"integrity": "sha512-m57UMER23Mk6Drg9OjtHW1Y+0KPGyZfE5XJoPTOsLARLar6013kJj4X2HICt+iFLJqIgTahA/QAvSn9lwF1EEw==" "integrity": "sha512-CnD7zLItIzt86q4Sj3kZUiLcBk1dSk81qcqgMGaZe7SQ1P8hFNxhMl5AZthK1zrDM5m74VVhaOpuMGIL4gagaA=="
}, },
"@humanwhocodes/config-array": { "@humanwhocodes/config-array": {
"version": "0.10.4", "version": "0.10.4",
@ -16444,8 +16437,8 @@
"dev": true "dev": true
}, },
"@matrix-org/olm": { "@matrix-org/olm": {
"version": "https://gitlab.matrix.org/api/v4/projects/27/packages/npm/@matrix-org/olm/-/@matrix-org/olm-3.2.8.tgz", "version": "https://gitlab.matrix.org/api/v4/projects/27/packages/npm/@matrix-org/olm/-/@matrix-org/olm-3.2.12.tgz",
"integrity": "sha512-yCJzEYY2aG1z+7nxKYZC4DFYwQO/5iG019qgotJhauYJRhEG9gLrKTvXO6lRHS8TjnZzsZFZyO/hQUlI4Dryig==" "integrity": "sha512-muHkYUAXyRDg88YVFlmFY35vgLPovK2YPkuEtBfgnmBcxJvLpV9UMcMMxNkf8opjMV1k/NJ4niFQMzwd4UQOiA=="
}, },
"@nodelib/fs.scandir": { "@nodelib/fs.scandir": {
"version": "2.1.5", "version": "2.1.5",
@ -16967,14 +16960,15 @@
"resolved": "https://registry.npmjs.org/ajv-formats/-/ajv-formats-2.1.1.tgz", "resolved": "https://registry.npmjs.org/ajv-formats/-/ajv-formats-2.1.1.tgz",
"integrity": "sha512-Wx0Kx52hxE7C18hkMEggYlEifqWZtYaRgouJor+WMdPnQyEK13vgEWyVNup7SoeeoLMsr4kf5h6dOW11I15MUA==", "integrity": "sha512-Wx0Kx52hxE7C18hkMEggYlEifqWZtYaRgouJor+WMdPnQyEK13vgEWyVNup7SoeeoLMsr4kf5h6dOW11I15MUA==",
"dev": true, "dev": true,
"requires": {}, "requires": {
"ajv": "^8.0.0"
},
"dependencies": { "dependencies": {
"ajv": { "ajv": {
"version": "https://registry.npmjs.org/ajv/-/ajv-8.9.0.tgz", "version": "8.9.0",
"resolved": "https://registry.npmjs.org/ajv/-/ajv-8.9.0.tgz",
"integrity": "sha512-qOKJyNj/h+OWx7s5DePL6Zu1KeM9jPZhwBqs+7DzP6bGOvqzVCSf0xueYmVuaC/oQ/VtS2zLMLHdQFbkka+XDQ==", "integrity": "sha512-qOKJyNj/h+OWx7s5DePL6Zu1KeM9jPZhwBqs+7DzP6bGOvqzVCSf0xueYmVuaC/oQ/VtS2zLMLHdQFbkka+XDQ==",
"dev": true, "dev": true,
"optional": true,
"peer": true,
"requires": { "requires": {
"fast-deep-equal": "^3.1.1", "fast-deep-equal": "^3.1.1",
"json-schema-traverse": "^1.0.0", "json-schema-traverse": "^1.0.0",
@ -16986,9 +16980,7 @@
"version": "1.0.0", "version": "1.0.0",
"resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz",
"integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==", "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==",
"dev": true, "dev": true
"optional": true,
"peer": true
} }
} }
}, },
@ -17347,12 +17339,9 @@
"integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==" "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw=="
}, },
"base-x": { "base-x": {
"version": "3.0.9", "version": "4.0.0",
"resolved": "https://registry.npmjs.org/base-x/-/base-x-3.0.9.tgz", "resolved": "https://registry.npmjs.org/base-x/-/base-x-4.0.0.tgz",
"integrity": "sha512-H7JU6iBHTal1gp56aKoaa//YUxEaAOUiydvrV/pILqIHXTtqxSkATOnDA2u+jZ/61sD+L/412+7kzXRtWukhpQ==", "integrity": "sha512-FuwxlW4H5kh37X/oW59pwTzzTKRzfrrQwhmyspRM7swOEZcHtDZSCt45U6oKgtuFE+WYPblePMVIPR4RZrh/hw=="
"requires": {
"safe-buffer": "^5.0.1"
}
}, },
"base64-js": { "base64-js": {
"version": "1.5.1", "version": "1.5.1",
@ -17632,11 +17621,11 @@
} }
}, },
"bs58": { "bs58": {
"version": "4.0.1", "version": "5.0.0",
"resolved": "https://registry.npmjs.org/bs58/-/bs58-4.0.1.tgz", "resolved": "https://registry.npmjs.org/bs58/-/bs58-5.0.0.tgz",
"integrity": "sha1-vhYedsNU9veIrkBx9j806MTwpCo=", "integrity": "sha512-r+ihvQJvahgYT50JD05dyJNKlmmSlMoOGwn1lCcEzanPglg7TxYjioQUYehQ9mAR/+hOSd2jRc/Z2y5UxBymvQ==",
"requires": { "requires": {
"base-x": "^3.0.2" "base-x": "^4.0.0"
} }
}, },
"buffer": { "buffer": {
@ -21794,18 +21783,18 @@
"integrity": "sha512-9jl4wtWanUFSy2sr2lCjErN/oC8KTAtaeaozJtrgot1JiQcEI4Rda9OLgQ7nLKaqb4Z/QUx/fR3XpDzm5Jy1JA==" "integrity": "sha512-9jl4wtWanUFSy2sr2lCjErN/oC8KTAtaeaozJtrgot1JiQcEI4Rda9OLgQ7nLKaqb4Z/QUx/fR3XpDzm5Jy1JA=="
}, },
"matrix-js-sdk": { "matrix-js-sdk": {
"version": "18.1.0", "version": "19.2.0",
"resolved": "https://registry.npmjs.org/matrix-js-sdk/-/matrix-js-sdk-18.1.0.tgz", "resolved": "https://registry.npmjs.org/matrix-js-sdk/-/matrix-js-sdk-19.2.0.tgz",
"integrity": "sha512-O5D36paIsY7a2M2mOo7KKU7v1Mb3PVkmYKupXYcXd9gB/Ki1K4mds+vSDEhgkKyKwk6MK1AV/vgvp0xJCsttvg==", "integrity": "sha512-alvTasCTCo/XXSIkKEj8xKe1NMsyiVDDVIQdU9ZHI1aePq+DrAcx8CqB7L/dgjk842v+63Eke1f/jZuFWvjn4w==",
"requires": { "requires": {
"@babel/runtime": "^7.12.5", "@babel/runtime": "^7.12.5",
"another-json": "^0.2.0", "another-json": "^0.2.0",
"browser-request": "^0.3.3", "browser-request": "^0.3.3",
"bs58": "^4.0.1", "bs58": "^5.0.0",
"content-type": "^1.0.4", "content-type": "^1.0.4",
"loglevel": "^1.7.1", "loglevel": "^1.7.1",
"matrix-events-sdk": "^0.0.1-beta.7", "matrix-events-sdk": "^0.0.1-beta.7",
"p-retry": "^4.5.0", "p-retry": "4",
"qs": "^6.9.6", "qs": "^6.9.6",
"request": "^2.88.2", "request": "^2.88.2",
"unhomoglyph": "^1.0.6" "unhomoglyph": "^1.0.6"
@ -23996,9 +23985,9 @@
} }
}, },
"sass": { "sass": {
"version": "1.54.1", "version": "1.54.3",
"resolved": "https://registry.npmjs.org/sass/-/sass-1.54.1.tgz", "resolved": "https://registry.npmjs.org/sass/-/sass-1.54.3.tgz",
"integrity": "sha512-GHJJr31Me32RjjUBagyzx8tzjKBUcDwo5239XANIRBq0adDu5iIG0aFO0i/TBb/4I9oyxkEv44nq/kL1DxdDhA==", "integrity": "sha512-fLodey5Qd41Pxp/Tk7Al97sViYwF/TazRc5t6E65O7JOk4XF8pzwIW7CvCxYVOfJFFI/1x5+elDyBIixrp+zrw==",
"dev": true, "dev": true,
"requires": { "requires": {
"chokidar": ">=3.0.0 <4.0.0", "chokidar": ">=3.0.0 <4.0.0",

View file

@ -1,6 +1,6 @@
{ {
"name": "cinny", "name": "cinny",
"version": "2.0.4", "version": "2.1.2",
"description": "Yet another matrix client", "description": "Yet another matrix client",
"main": "index.js", "main": "index.js",
"engines": { "engines": {
@ -16,9 +16,9 @@
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
"@alienfast/i18next-loader": "^1.1.4", "@alienfast/i18next-loader": "^1.1.4",
"@fontsource/inter": "^4.5.11", "@fontsource/inter": "^4.5.12",
"@fontsource/roboto": "^4.5.7", "@fontsource/roboto": "^4.5.8",
"@matrix-org/olm": "https://gitlab.matrix.org/api/v4/projects/27/packages/npm/@matrix-org/olm/-/@matrix-org/olm-3.2.8.tgz", "@matrix-org/olm": "https://gitlab.matrix.org/api/v4/projects/27/packages/npm/@matrix-org/olm/-/@matrix-org/olm-3.2.12.tgz",
"@tippyjs/react": "^4.2.6", "@tippyjs/react": "^4.2.6",
"babel-polyfill": "^6.26.0", "babel-polyfill": "^6.26.0",
"blurhash": "^1.1.5", "blurhash": "^1.1.5",
@ -35,7 +35,7 @@
"katex": "^0.16.0", "katex": "^0.16.0",
"linkify-html": "^4.0.0-beta.5", "linkify-html": "^4.0.0-beta.5",
"linkifyjs": "^4.0.0-beta.5", "linkifyjs": "^4.0.0-beta.5",
"matrix-js-sdk": "^18.1.0", "matrix-js-sdk": "^19.2.0",
"micromark": "^3.0.10", "micromark": "^3.0.10",
"micromark-extension-gfm": "^2.0.1", "micromark-extension-gfm": "^2.0.1",
"micromark-extension-math": "^2.0.2", "micromark-extension-math": "^2.0.2",
@ -81,7 +81,7 @@
"html-webpack-plugin": "^5.3.1", "html-webpack-plugin": "^5.3.1",
"mini-css-extract-plugin": "^2.6.1", "mini-css-extract-plugin": "^2.6.1",
"path-browserify": "^1.0.1", "path-browserify": "^1.0.1",
"sass": "^1.54.1", "sass": "^1.54.3",
"sass-loader": "^13.0.2", "sass-loader": "^13.0.2",
"stream-browserify": "^3.0.0", "stream-browserify": "^3.0.0",
"style-loader": "^3.3.1", "style-loader": "^3.3.1",

View file

@ -16,6 +16,7 @@ function Input({
{ resizable { resizable
? ( ? (
<TextareaAutosize <TextareaAutosize
dir="auto"
style={{ minHeight: `${minHeight}px` }} style={{ minHeight: `${minHeight}px` }}
name={name} name={name}
id={id} id={id}
@ -34,6 +35,7 @@ function Input({
/> />
) : ( ) : (
<input <input
dir="auto"
ref={forwardRef} ref={forwardRef}
id={id} id={id}
name={name} name={name}

View file

@ -123,7 +123,7 @@ function useImagePackHandles(pack, sendPackContent) {
const getNewKey = (key) => { const getNewKey = (key) => {
if (typeof key !== 'string') return undefined; if (typeof key !== 'string') return undefined;
let newKey = key?.replace(/\s/g, '-'); let newKey = key?.replace(/\s/g, '_');
if (pack.getImages().get(newKey)) { if (pack.getImages().get(newKey)) {
newKey = suffixRename( newKey = suffixRename(
newKey, newKey,

View file

@ -44,11 +44,13 @@ function ImagePackUpload({ onUpload }) {
const img = evt.target.files[0]; const img = evt.target.files[0];
if (!img) return; if (!img) return;
setImgFile(img); setImgFile(img);
shortcodeRef.current.value = img.name.slice(0, img.name.indexOf('.'));
shortcodeRef.current.focus(); shortcodeRef.current.focus();
}; };
const handleRemove = () => { const handleRemove = () => {
setImgFile(null); setImgFile(null);
inputRef.current.value = null; inputRef.current.value = null;
shortcodeRef.current.value = '';
}; };
return ( return (

View file

@ -15,43 +15,7 @@ import ExternalSVG from '../../../../public/res/ic/outlined/external.svg';
import PlaySVG from '../../../../public/res/ic/outlined/play.svg'; import PlaySVG from '../../../../public/res/ic/outlined/play.svg';
import '../../i18n'; import '../../i18n';
import { getBlobSafeMimeType } from '../../../util/mimetypes';
// https://github.com/matrix-org/matrix-react-sdk/blob/cd15e08fc285da42134817cce50de8011809cd53/src/utils/blobs.ts#L73
const ALLOWED_BLOB_MIMETYPES = [
'image/jpeg',
'image/gif',
'image/png',
'image/apng',
'image/webp',
'image/avif',
'video/mp4',
'video/webm',
'video/ogg',
'video/quicktime',
'audio/mp4',
'audio/webm',
'audio/aac',
'audio/mpeg',
'audio/ogg',
'audio/wave',
'audio/wav',
'audio/x-wav',
'audio/x-pn-wav',
'audio/flac',
'audio/x-flac',
];
function getBlobSafeMimeType(mimetype) {
if (!ALLOWED_BLOB_MIMETYPES.includes(mimetype)) {
return 'application/octet-stream';
}
// Required for Chromium browsers
if (mimetype === 'video/quicktime') {
return 'video/mp4';
}
return mimetype;
}
async function getDecryptedBlob(response, type, decryptData) { async function getDecryptedBlob(response, type, decryptData) {
const arrayBuffer = await response.arrayBuffer(); const arrayBuffer = await response.arrayBuffer();
@ -163,6 +127,7 @@ function Image({
name, width, height, link, file, type, blurhash, name, width, height, link, file, type, blurhash,
}) { }) {
const [url, setUrl] = useState(null); const [url, setUrl] = useState(null);
const [blur, setBlur] = useState(true);
useEffect(() => { useEffect(() => {
let unmounted = false; let unmounted = false;
@ -181,8 +146,8 @@ function Image({
<div className="file-container"> <div className="file-container">
<FileHeader name={name} link={url || link} type={type} external /> <FileHeader name={name} link={url || link} type={type} external />
<div style={{ height: width !== null ? getNativeHeight(width, height) : 'unset' }} className="image-container"> <div style={{ height: width !== null ? getNativeHeight(width, height) : 'unset' }} className="image-container">
{ blurhash && <BlurhashCanvas hash={blurhash} punch={1} />} { blurhash && blur && <BlurhashCanvas hash={blurhash} punch={1} />}
{ url !== null && <img src={url || link} alt={name} />} { url !== null && <img style={{ display: blur ? 'none' : 'unset' }} onLoad={() => setBlur(false)} src={url || link} alt={name} />}
</div> </div>
</div> </div>
); );
@ -231,11 +196,11 @@ function Sticker({
Sticker.defaultProps = { Sticker.defaultProps = {
file: null, file: null,
type: '', type: '',
width: null,
height: null,
}; };
Sticker.propTypes = { Sticker.propTypes = {
name: PropTypes.string.isRequired, name: PropTypes.string.isRequired,
width: null,
height: null,
width: PropTypes.number, width: PropTypes.number,
height: PropTypes.number, height: PropTypes.number,
link: PropTypes.string.isRequired, link: PropTypes.string.isRequired,
@ -295,6 +260,7 @@ function Video({
const [isLoading, setIsLoading] = useState(false); const [isLoading, setIsLoading] = useState(false);
const [url, setUrl] = useState(null); const [url, setUrl] = useState(null);
const [thumbUrl, setThumbUrl] = useState(null); const [thumbUrl, setThumbUrl] = useState(null);
const [blur, setBlur] = useState(true);
useEffect(() => { useEffect(() => {
let unmounted = false; let unmounted = false;
@ -309,16 +275,16 @@ function Video({
}; };
}, []); }, []);
async function loadVideo() { const loadVideo = async () => {
const myUrl = await getUrl(link, type, file); const myUrl = await getUrl(link, type, file);
setUrl(myUrl); setUrl(myUrl);
setIsLoading(false); setIsLoading(false);
} };
function handlePlayVideo() { const handlePlayVideo = () => {
setIsLoading(true); setIsLoading(true);
loadVideo(); loadVideo();
} };
const { t } = useTranslation(); const { t } = useTranslation();
@ -331,14 +297,16 @@ function Video({
}} }}
className="video-container" className="video-container"
> >
{ url === null && blurhash && <BlurhashCanvas hash={blurhash} punch={1} />} { url === null ? (
{ url === null && thumbUrl !== null && ( <>
/* eslint-disable-next-line jsx-a11y/alt-text */ { blurhash && blur && <BlurhashCanvas hash={blurhash} punch={1} />}
<img src={thumbUrl} /> { thumbUrl !== null && (
<img style={{ display: blur ? 'none' : 'unset' }} src={thumbUrl} onLoad={() => setBlur(false)} alt={name} />
)} )}
{ url === null && isLoading && <Spinner size="small" /> } {isLoading && <Spinner size="small" />}
{ url === null && !isLoading && <IconButton onClick={handlePlayVideo} tooltip={t('Molecules.Media.play_video')} src={PlaySVG} />} {!isLoading && <IconButton onClick={handlePlayVideo} tooltip={t('Molecules.Media.play_video')} src={PlaySVG} />}
{ url !== null && ( </>
) : (
/* eslint-disable-next-line jsx-a11y/media-has-caption */ /* eslint-disable-next-line jsx-a11y/media-has-caption */
<video autoPlay controls poster={thumbUrl}> <video autoPlay controls poster={thumbUrl}>
<source src={url} type={getBlobSafeMimeType(type)} /> <source src={url} type={getBlobSafeMimeType(type)} />

View file

@ -27,14 +27,21 @@
white-space: initial; white-space: initial;
} }
.sticker-container {
display: inline-flex;
max-width: 128px;
width: 100%;
& img {
width: 100% !important;
}
}
.image-container, .image-container,
.video-container, .video-container,
.audio-container { .audio-container {
font-size: 0; font-size: 0;
line-height: 0; line-height: 0;
position: relative;
display: flex; display: flex;
justify-content: center; justify-content: center;
align-items: center; align-items: center;
@ -48,7 +55,6 @@
.video-container { .video-container {
& img, & img,
& canvas { & canvas {
position: absolute;
max-width: unset !important; max-width: unset !important;
width: 100% !important; width: 100% !important;
height: 100%; height: 100%;
@ -57,18 +63,13 @@
} }
} }
.sticker-container {
display: inline-flex;
max-width: 128px;
width: 100%;
& img {
width: 100% !important;
}
}
.video-container { .video-container {
position: relative;
& .ic-btn-surface { & .ic-btn-surface {
background-color: var(--bg-surface-low); background-color: var(--bg-surface-low);
}
& .ic-btn-surface,
& .donut-spinner {
position: absolute; position: absolute;
} }
video { video {

View file

@ -38,6 +38,7 @@ import CmdIC from '../../../../public/res/ic/outlined/cmd.svg';
import BinIC from '../../../../public/res/ic/outlined/bin.svg'; import BinIC from '../../../../public/res/ic/outlined/bin.svg';
import { confirmDialog } from '../confirm-dialog/ConfirmDialog'; import { confirmDialog } from '../confirm-dialog/ConfirmDialog';
import { getBlobSafeMimeType } from '../../../util/mimetypes';
import '../../i18n'; import '../../i18n';
@ -210,7 +211,13 @@ const MessageBody = React.memo(({
let content = null; let content = null;
if (isCustomHTML) { if (isCustomHTML) {
try { try {
content = twemojify(sanitizeCustomHtml(body), undefined, true, false, true); content = twemojify(
sanitizeCustomHtml(initMatrix.matrixClient, body),
undefined,
true,
false,
true,
);
} catch { } catch {
console.error('Malformed custom html: ', body); console.error('Malformed custom html: ', body);
content = twemojify(body, undefined); content = twemojify(body, undefined);
@ -626,7 +633,12 @@ function genMediaContent(mE) {
if (typeof mediaMXC === 'undefined' || mediaMXC === '') return <span style={{ color: 'var(--bg-danger)' }}>Malformed event</span>; if (typeof mediaMXC === 'undefined' || mediaMXC === '') return <span style={{ color: 'var(--bg-danger)' }}>Malformed event</span>;
let msgType = mE.getContent()?.msgtype; let msgType = mE.getContent()?.msgtype;
if (mE.getType() === 'm.sticker') msgType = 'm.sticker'; const safeMimetype = getBlobSafeMimeType(mContent.info?.mimetype);
if (mE.getType() === 'm.sticker') {
msgType = 'm.sticker';
} else if (safeMimetype === 'application/octet-stream') {
msgType = 'm.file';
}
const blurhash = mContent?.info?.['xyz.amorgan.blurhash']; const blurhash = mContent?.info?.['xyz.amorgan.blurhash'];

View file

@ -252,6 +252,58 @@ function EmojiBoard({ onSelect, searchRef }) {
return ( return (
<div id="emoji-board" className="emoji-board"> <div id="emoji-board" className="emoji-board">
<ScrollView invisible>
<div className="emoji-board__nav">
{recentEmojis.length > 0 && (
<IconButton
onClick={() => openGroup(0)}
src={RecentClockIC}
tooltip="Recent"
tooltipPlacement="left"
/>
)}
<div className="emoji-board__nav-custom">
{
availableEmojis.map((pack) => {
const src = initMatrix.matrixClient
.mxcUrlToHttp(pack.avatarUrl ?? pack.getEmojis()[0].mxc);
return (
<IconButton
onClick={() => openGroup(recentOffset + pack.packIndex)}
src={src}
key={pack.packIndex}
tooltip={pack.displayName ?? 'Unknown'}
tooltipPlacement="left"
isImage
/>
);
})
}
</div>
<div className="emoji-board__nav-twemoji">
{
[
[0, EmojiIC, 'Smilies'],
[1, DogIC, 'Animals'],
[2, CupIC, 'Food'],
[3, BallIC, 'Activities'],
[4, PhotoIC, 'Travel'],
[5, BulbIC, 'Objects'],
[6, PeaceIC, 'Symbols'],
[7, FlagIC, 'Flags'],
].map(([indx, ico, name]) => (
<IconButton
onClick={() => openGroup(recentOffset + availableEmojis.length + indx)}
key={indx}
src={ico}
tooltip={name}
tooltipPlacement="left"
/>
))
}
</div>
</div>
</ScrollView>
<div className="emoji-board__content"> <div className="emoji-board__content">
<div className="emoji-board__content__search"> <div className="emoji-board__content__search">
<RawIcon size="small" src={SearchIC} /> <RawIcon size="small" src={SearchIC} />
@ -285,58 +337,6 @@ function EmojiBoard({ onSelect, searchRef }) {
<Text>:slight_smile:</Text> <Text>:slight_smile:</Text>
</div> </div>
</div> </div>
<ScrollView invisible>
<div className="emoji-board__nav">
{recentEmojis.length > 0 && (
<IconButton
onClick={() => openGroup(0)}
src={RecentClockIC}
tooltip="Recent"
tooltipPlacement="right"
/>
)}
<div className="emoji-board__nav-custom">
{
availableEmojis.map((pack) => {
const src = initMatrix.matrixClient
.mxcUrlToHttp(pack.avatarUrl ?? pack.getEmojis()[0].mxc);
return (
<IconButton
onClick={() => openGroup(recentOffset + pack.packIndex)}
src={src}
key={pack.packIndex}
tooltip={pack.displayName ?? 'Unknown'}
tooltipPlacement="right"
isImage
/>
);
})
}
</div>
<div className="emoji-board__nav-twemoji">
{
[
[0, EmojiIC, 'Smilies'],
[1, DogIC, 'Animals'],
[2, CupIC, 'Food'],
[3, BallIC, 'Activities'],
[4, PhotoIC, 'Travel'],
[5, BulbIC, 'Objects'],
[6, PeaceIC, 'Symbols'],
[7, FlagIC, 'Flags'],
].map(([indx, ico, name]) => (
<IconButton
onClick={() => openGroup(recentOffset + availableEmojis.length + indx)}
key={indx}
src={ico}
tooltip={name}
tooltipPlacement="right"
/>
))
}
</div>
</div>
</ScrollView>
</div> </div>
); );
} }

View file

@ -25,8 +25,7 @@
min-height: 100%; min-height: 100%;
padding: 4px 6px; padding: 4px 6px;
background-color: var(--bg-surface-low); @include dir.side(border, none, 1px solid var(--bg-surface-border));
@include dir.side(border, 1px solid var(--bg-surface-border), none);
position: relative; position: relative;
@ -122,8 +121,11 @@
@include dir.side(margin, var(--left-margin), var(--right-margin)); @include dir.side(margin, var(--left-margin), var(--right-margin));
} }
& .emoji { & .emoji {
width: 38px; max-width: 38px;
height: 38px; max-height: 38px;
width: 100%;
height: 100%;
overflow: hidden;
object-fit: contain; object-fit: contain;
padding: var(--emoji-padding); padding: var(--emoji-padding);
cursor: pointer; cursor: pointer;

View file

@ -342,6 +342,7 @@ function RoomViewInput({
<ScrollView autoHide> <ScrollView autoHide>
<Text className="room-input__textarea-wrapper"> <Text className="room-input__textarea-wrapper">
<TextareaAutosize <TextareaAutosize
dir="auto"
id="message-textarea" id="message-textarea"
ref={textAreaRef} ref={textAreaRef}
onChange={handleMsgTyping} onChange={handleMsgTyping}

View file

@ -206,7 +206,7 @@ function getUsersActionJsx(roomId, userIds, actionStr) {
const othersCount = userIds.length - MAX_VISIBLE_COUNT; const othersCount = userIds.length - MAX_VISIBLE_COUNT;
// eslint-disable-next-line react/jsx-one-expression-per-line // eslint-disable-next-line react/jsx-one-expression-per-line
return <>{u1Jsx}, {u2Jsx}, {u3Jsx} and {othersCount} other are {actionStr}</>; return <>{u1Jsx}, {u2Jsx}, {u3Jsx} and {othersCount} others are {actionStr}</>;
} }
function parseTimelineChange(mEvent) { function parseTimelineChange(mEvent) {

View file

@ -1,6 +1,6 @@
/* eslint-disable jsx-a11y/click-events-have-key-events */ /* eslint-disable jsx-a11y/click-events-have-key-events */
/* eslint-disable jsx-a11y/no-static-element-interactions */ /* eslint-disable jsx-a11y/no-static-element-interactions */
import React from 'react'; import React, { useRef } from 'react';
import PropTypes from 'prop-types'; import PropTypes from 'prop-types';
import './StickerBoard.scss'; import './StickerBoard.scss';
@ -9,10 +9,12 @@ import { getRelevantPacks } from '../emoji-board/custom-emoji';
import Text from '../../atoms/text/Text'; import Text from '../../atoms/text/Text';
import ScrollView from '../../atoms/scroll/ScrollView'; import ScrollView from '../../atoms/scroll/ScrollView';
import IconButton from '../../atoms/button/IconButton';
function StickerBoard({ roomId, onSelect }) { function StickerBoard({ roomId, onSelect }) {
const mx = initMatrix.matrixClient; const mx = initMatrix.matrixClient;
const room = mx.getRoom(roomId); const room = mx.getRoom(roomId);
const scrollRef = useRef(null);
const parentIds = initMatrix.roomList.getAllParentSpaces(room.roomId); const parentIds = initMatrix.roomList.getAllParentSpaces(room.roomId);
const parentRooms = [...parentIds].map((id) => mx.getRoom(id)); const parentRooms = [...parentIds].map((id) => mx.getRoom(id));
@ -38,6 +40,11 @@ function StickerBoard({ roomId, onSelect }) {
onSelect(stickerData); onSelect(stickerData);
}; };
const openGroup = (groupIndex) => {
const scrollContent = scrollRef.current.firstElementChild;
scrollContent.children[groupIndex].scrollIntoView();
};
const renderPack = (pack) => ( const renderPack = (pack) => (
<div className="sticker-board__pack" key={pack.id}> <div className="sticker-board__pack" key={pack.id}>
<Text className="sticker-board__pack-header" variant="b2" weight="bold">{pack.displayName ?? 'Unknown'}</Text> <Text className="sticker-board__pack-header" variant="b2" weight="bold">{pack.displayName ?? 'Unknown'}</Text>
@ -50,6 +57,7 @@ function StickerBoard({ roomId, onSelect }) {
alt={sticker.shortcode} alt={sticker.shortcode}
title={sticker.body ?? sticker.shortcode} title={sticker.body ?? sticker.shortcode}
data-mx-sticker={sticker.mxc} data-mx-sticker={sticker.mxc}
loading="lazy"
/> />
))} ))}
</div> </div>
@ -58,8 +66,27 @@ function StickerBoard({ roomId, onSelect }) {
return ( return (
<div className="sticker-board"> <div className="sticker-board">
{packs.length > 0 && (
<ScrollView invisible>
<div className="sticker-board__sidebar">
{packs.map((pack, index) => {
const src = mx.mxcUrlToHttp(pack.avatarUrl ?? pack.getStickers()[0].mxc);
return (
<IconButton
key={pack.id}
onClick={() => openGroup(index)}
src={src}
tooltip={pack.displayName || 'Unknown'}
tooltipPlacement="left"
isImage
/>
);
})}
</div>
</ScrollView>
)}
<div className="sticker-board__container"> <div className="sticker-board__container">
<ScrollView autoHide> <ScrollView autoHide ref={scrollRef}>
<div <div
onClick={handleOnSelect} onClick={handleOnSelect}
className="sticker-board__content" className="sticker-board__content"

View file

@ -5,6 +5,20 @@
--sticker-board-width: 286px; --sticker-board-width: 286px;
display: flex; display: flex;
height: var(--sticker-board-height); height: var(--sticker-board-height);
display: flex;
& > .scrollbar {
width: initial;
height: var(--sticker-board-height);
}
&__sidebar {
display: flex;
flex-direction: column;
min-height: 100%;
padding: 4px 6px;
@include dir.side(border, none, 1px solid var(--bg-surface-border));
}
&__container { &__container {
flex-grow: 1; flex-grow: 1;

View file

@ -1,13 +1,16 @@
import initMatrix from '../initMatrix'; import initMatrix from '../initMatrix';
function logout() { async function logout() {
const mx = initMatrix.matrixClient; const mx = initMatrix.matrixClient;
mx.stopClient(); mx.stopClient();
mx.logout().then(() => { try {
await mx.logout();
} catch {
// ignore if failed to logout
}
mx.clearStores(); mx.clearStores();
window.localStorage.clear(); window.localStorage.clear();
window.location.reload(); window.location.reload();
});
} }
export default logout; export default logout;

View file

@ -33,7 +33,6 @@ class InitMatrix extends EventEmitter {
accessToken: secret.accessToken, accessToken: secret.accessToken,
userId: secret.userId, userId: secret.userId,
store: indexedDBStore, store: indexedDBStore,
sessionStore: new sdk.WebStorageSessionStore(global.localStorage),
cryptoStore: new sdk.IndexedDBCryptoStore(global.indexedDB, 'crypto-store'), cryptoStore: new sdk.IndexedDBCryptoStore(global.indexedDB, 'crypto-store'),
deviceId: secret.deviceId, deviceId: secret.deviceId,
timelineSupport: true, timelineSupport: true,

View file

@ -6,10 +6,14 @@ import { math } from 'micromark-extension-math';
import { encode } from 'blurhash'; import { encode } from 'blurhash';
import { getShortcodeToEmoji } from '../../app/organisms/emoji-board/custom-emoji'; import { getShortcodeToEmoji } from '../../app/organisms/emoji-board/custom-emoji';
import { mathExtensionHtml, spoilerExtension, spoilerExtensionHtml } from '../../util/markdown'; import { mathExtensionHtml, spoilerExtension, spoilerExtensionHtml } from '../../util/markdown';
import { getBlobSafeMimeType } from '../../util/mimetypes';
import { sanitizeText } from '../../util/sanitize';
import cons from './cons'; import cons from './cons';
import settings from './settings'; import settings from './settings';
const blurhashField = 'xyz.amorgan.blurhash'; const blurhashField = 'xyz.amorgan.blurhash';
const MXID_REGEX = /\B@\S+:\S+\.\S+[^.,:;?!\s]/g;
const SHORTCODE_REGEX = /\B:([\w-]+):\B/g;
function encodeBlurhash(img) { function encodeBlurhash(img) {
const canvas = document.createElement('canvas'); const canvas = document.createElement('canvas');
@ -130,38 +134,45 @@ function bindReplyToContent(roomId, reply, content) {
return newContent; return newContent;
} }
function formatAndEmojifyText(mx, roomList, roomId, text) { function findAndReplace(text, regex, filter, replace) {
const room = mx.getRoom(roomId); let copyText = text;
Array.from(copyText.matchAll(regex))
.filter(filter)
.reverse() /* to replace backward to forward */
.forEach((match) => {
const matchText = match[0];
const tag = replace(match);
copyText = copyText.substr(0, match.index)
+ tag
+ copyText.substr(match.index + matchText.length);
});
return copyText;
}
function formatUserPill(room, text) {
const { userIdsToDisplayNames } = room.currentState; const { userIdsToDisplayNames } = room.currentState;
const parentIds = roomList.getAllParentSpaces(roomId); return findAndReplace(
text,
MXID_REGEX,
(match) => userIdsToDisplayNames[match[0]],
(match) => (
`<a href="https://matrix.to/#/${match[0]}">@${userIdsToDisplayNames[match[0]]}</a>`
),
);
}
function formatEmoji(mx, room, roomList, text) {
const parentIds = roomList.getAllParentSpaces(room.roomId);
const parentRooms = [...parentIds].map((id) => mx.getRoom(id)); const parentRooms = [...parentIds].map((id) => mx.getRoom(id));
const allEmoji = getShortcodeToEmoji(mx, [room, ...parentRooms]); const allEmoji = getShortcodeToEmoji(mx, [room, ...parentRooms]);
let formattedText; return findAndReplace(
if (settings.isMarkdown) { text,
formattedText = getFormattedBody(text); SHORTCODE_REGEX,
} else { (match) => allEmoji.has(match[1]),
formattedText = text; (match) => {
} const emoji = allEmoji.get(match[1]);
const MXID_REGEX = /\B@\S+:\S+\.\S+[^.,:;?!\s]/g;
Array.from(formattedText.matchAll(MXID_REGEX))
.filter((mxidMatch) => userIdsToDisplayNames[mxidMatch[0]])
.reverse()
.forEach((mxidMatch) => {
const tag = `<a href="https://matrix.to/#/${mxidMatch[0]}">${userIdsToDisplayNames[mxidMatch[0]]}</a>`;
formattedText = formattedText.substr(0, mxidMatch.index)
+ tag
+ formattedText.substr(mxidMatch.index + mxidMatch[0].length);
});
const SHORTCODE_REGEX = /\B:([\w-]+):\B/g;
Array.from(formattedText.matchAll(SHORTCODE_REGEX))
.filter((shortcodeMatch) => allEmoji.has(shortcodeMatch[1]))
.reverse() /* Reversing the array ensures that indices are preserved as we start replacing */
.forEach((shortcodeMatch) => {
const emoji = allEmoji.get(shortcodeMatch[1]);
let tag; let tag;
if (emoji.mxc) { if (emoji.mxc) {
@ -175,13 +186,9 @@ function formatAndEmojifyText(mx, roomList, roomId, text) {
} else { } else {
tag = emoji.unicode; tag = emoji.unicode;
} }
return tag;
formattedText = formattedText.substr(0, shortcodeMatch.index) },
+ tag );
+ formattedText.substr(shortcodeMatch.index + shortcodeMatch[0].length);
});
return formattedText;
} }
class RoomsInput extends EventEmitter { class RoomsInput extends EventEmitter {
@ -274,6 +281,7 @@ class RoomsInput extends EventEmitter {
} }
async sendInput(roomId) { async sendInput(roomId) {
const room = this.matrixClient.getRoom(roomId);
const input = this.getInput(roomId); const input = this.getInput(roomId);
input.isSending = true; input.isSending = true;
this.roomIdToInput.set(roomId, input); this.roomIdToInput.set(roomId, input);
@ -283,19 +291,27 @@ class RoomsInput extends EventEmitter {
} }
if (this.getMessage(roomId).trim() !== '') { if (this.getMessage(roomId).trim() !== '') {
const rawMessage = input.message;
let content = { let content = {
body: input.message, body: rawMessage,
msgtype: 'm.text', msgtype: 'm.text',
}; };
// Apply formatting if relevant // Apply formatting if relevant
const formattedBody = formatAndEmojifyText( let formattedBody = settings.isMarkdown
this.matrixClient, ? getFormattedBody(rawMessage)
this.roomList, : sanitizeText(rawMessage);
roomId,
input.message, formattedBody = formatUserPill(room, formattedBody);
formattedBody = formatEmoji(this.matrixClient, room, this.roomList, formattedBody);
content.body = findAndReplace(
content.body,
MXID_REGEX,
(match) => room.currentState.userIdsToDisplayNames[match[0]],
(match) => `@${room.currentState.userIdsToDisplayNames[match[0]]}`,
); );
if (formattedBody !== input.message) { if (formattedBody !== sanitizeText(rawMessage)) {
// Formatting was applied, and we need to switch to custom HTML // Formatting was applied, and we need to switch to custom HTML
content.format = 'org.matrix.custom.html'; content.format = 'org.matrix.custom.html';
content.formatted_body = formattedBody; content.formatted_body = formattedBody;
@ -340,7 +356,7 @@ class RoomsInput extends EventEmitter {
} }
async sendFile(roomId, file) { async sendFile(roomId, file) {
const fileType = file.type.slice(0, file.type.indexOf('/')); const fileType = getBlobSafeMimeType(file.type).slice(0, file.type.indexOf('/'));
const info = { const info = {
mimetype: file.type, mimetype: file.type,
size: file.size, size: file.size,
@ -446,6 +462,7 @@ class RoomsInput extends EventEmitter {
} }
async sendEditedMessage(roomId, mEvent, editedBody) { async sendEditedMessage(roomId, mEvent, editedBody) {
const room = this.matrixClient.getRoom(roomId);
const isReply = typeof mEvent.getWireContent()['m.relates_to']?.['m.in_reply_to'] !== 'undefined'; const isReply = typeof mEvent.getWireContent()['m.relates_to']?.['m.in_reply_to'] !== 'undefined';
const content = { const content = {
@ -462,13 +479,19 @@ class RoomsInput extends EventEmitter {
}; };
// Apply formatting if relevant // Apply formatting if relevant
const formattedBody = formatAndEmojifyText( let formattedBody = settings.isMarkdown
this.matrixClient, ? getFormattedBody(editedBody)
this.roomList, : sanitizeText(editedBody);
roomId, formattedBody = formatUserPill(room, formattedBody);
editedBody, formattedBody = formatEmoji(this.matrixClient, room, this.roomList, formattedBody);
content.body = findAndReplace(
content.body,
MXID_REGEX,
(match) => room.currentState.userIdsToDisplayNames[match[0]],
(match) => `@${room.currentState.userIdsToDisplayNames[match[0]]}`,
); );
if (formattedBody !== editedBody) { if (formattedBody !== sanitizeText(editedBody)) {
content.formatted_body = ` * ${formattedBody}`; content.formatted_body = ` * ${formattedBody}`;
content.format = 'org.matrix.custom.html'; content.format = 'org.matrix.custom.html';
content['m.new_content'].formatted_body = formattedBody; content['m.new_content'].formatted_body = formattedBody;

View file

@ -1,5 +1,5 @@
const cons = { const cons = {
version: '2.0.4', version: '2.1.2',
secretKey: { secretKey: {
ACCESS_TOKEN: 'cinny_access_token', ACCESS_TOKEN: 'cinny_access_token',
DEVICE_ID: 'cinny_device_id', DEVICE_ID: 'cinny_device_id',

View file

@ -166,6 +166,9 @@ export function scaleDownImage(imageFile, width, height) {
img.onload = () => { img.onload = () => {
let newWidth = img.width; let newWidth = img.width;
let newHeight = img.height; let newHeight = img.height;
if (newHeight <= height && newWidth <= width) {
resolve(imageFile);
}
if (newHeight > height) { if (newHeight > height) {
newWidth = Math.floor(newWidth * (height / newHeight)); newWidth = Math.floor(newWidth * (height / newHeight));

37
src/util/mimetypes.js Normal file
View file

@ -0,0 +1,37 @@
// https://github.com/matrix-org/matrix-react-sdk/blob/cd15e08fc285da42134817cce50de8011809cd53/src/utils/blobs.ts
export const ALLOWED_BLOB_MIMETYPES = [
'image/jpeg',
'image/gif',
'image/png',
'image/apng',
'image/webp',
'image/avif',
'video/mp4',
'video/webm',
'video/ogg',
'video/quicktime',
'audio/mp4',
'audio/webm',
'audio/aac',
'audio/mpeg',
'audio/ogg',
'audio/wave',
'audio/wav',
'audio/x-wav',
'audio/x-pn-wav',
'audio/flac',
'audio/x-flac',
];
export function getBlobSafeMimeType(mimetype) {
if (!ALLOWED_BLOB_MIMETYPES.includes(mimetype)) {
return 'application/octet-stream';
}
// Required for Chromium browsers
if (mimetype === 'video/quicktime') {
return 'video/mp4';
}
return mimetype;
}

View file

@ -1,7 +1,7 @@
import sanitizeHtml from 'sanitize-html'; import sanitizeHtml from 'sanitize-html';
import initMatrix from '../client/initMatrix';
const MAX_TAG_NESTING = 100; const MAX_TAG_NESTING = 100;
let mx = null;
const permittedHtmlTags = [ const permittedHtmlTags = [
'font', 'del', 'h1', 'h2', 'h3', 'h4', 'h5', 'h6', 'font', 'del', 'h1', 'h2', 'h3', 'h4', 'h5', 'h6',
@ -54,7 +54,7 @@ function transformATag(tagName, attribs) {
'data-mx-pill': userId, 'data-mx-pill': userId,
}, },
}; };
if (userId === initMatrix.matrixClient.getUserId()) { if (userId === mx?.getUserId()) {
pill.attribs['data-mx-ping'] = undefined; pill.attribs['data-mx-ping'] = undefined;
} }
return pill; return pill;
@ -76,17 +76,28 @@ function transformATag(tagName, attribs) {
function transformImgTag(tagName, attribs) { function transformImgTag(tagName, attribs) {
const { src } = attribs; const { src } = attribs;
const mx = initMatrix.matrixClient; if (src.startsWith('mxc://') === false) {
return {
tagName: 'a',
attribs: {
href: src,
rel: 'noopener',
target: '_blank',
},
text: attribs.alt || src,
};
}
return { return {
tagName, tagName,
attribs: { attribs: {
...attribs, ...attribs,
src: src.startsWith('mxc://') ? mx.mxcUrlToHttp(src) : src, src: mx?.mxcUrlToHttp(src),
}, },
}; };
} }
export function sanitizeCustomHtml(body) { export function sanitizeCustomHtml(matrixClient, body) {
mx = matrixClient;
return sanitizeHtml(body, { return sanitizeHtml(body, {
allowedTags: permittedHtmlTags, allowedTags: permittedHtmlTags,
allowedAttributes: permittedTagToAttributes, allowedAttributes: permittedTagToAttributes,