Merge branch 'develop' into refactor/types
This commit is contained in:
commit
082948bfe0
129 changed files with 1759 additions and 1221 deletions
|
@ -178,19 +178,13 @@ logLevel: [
|
|||
# Media Proxy
|
||||
#mediaProxy: https://example.com/proxy
|
||||
|
||||
# Proxy remote files (default: false)
|
||||
# Proxy remote files (default: true)
|
||||
#proxyRemoteFiles: true
|
||||
|
||||
#allowedPrivateNetworks: [
|
||||
# '127.0.0.1/32'
|
||||
#]
|
||||
|
||||
# TWA
|
||||
#twa:
|
||||
# nameSpace: android_app
|
||||
# packageName: tld.domain.twa
|
||||
# sha256CertFingerprints: ['AB:CD:EF']
|
||||
|
||||
# Upload or download file size limits (bytes)
|
||||
#maxFileSize: 262144000
|
||||
|
||||
|
|
|
@ -3,30 +3,38 @@
|
|||
🔒 Found a security vulnerability? [Please disclose it responsibly.](https://firefish.dev/firefish/firefish/-/blob/develop/SECURITY.md)
|
||||
🤝 By submitting this issue, you agree to follow our [Contribution Guidelines.](https://firefish.dev/firefish/firefish/-/blob/develop/CONTRIBUTING.md) -->
|
||||
|
||||
**What happened?** _(Please give us a brief description of what happened.)_
|
||||
## What happened? <!-- Please give us a brief description of what happened. -->
|
||||
|
||||
**What did you expect to happen?** _(Please give us a brief description of what you expected to happen.)_
|
||||
## What did you expect to happen? <!-- Please give us a brief description of what you expected to happen. -->
|
||||
|
||||
**Version** _(What version of firefish is your instance running? You can find this by clicking your instance's logo at the bottom left and then clicking instance information.)_
|
||||
## Version <!-- What version of firefish is your instance running? You can find this by clicking your instance's logo at the bottom left and then clicking instance information. -->
|
||||
|
||||
**Instance** _(What instance of firefish are you using?)_
|
||||
## What type of issue is this? <!-- If this happens on your device and has to do with the user interface, it's client-side. If this happens on either with the API or the backend, or you got a server-side error in the client, it's server-side. -->
|
||||
|
||||
**What type of issue is this?** _(If this happens on your device and has to do with the user interface, it's client-side. If this happens on either with the API or the backend, or you got a server-side error in the client, it's server-side.)_
|
||||
- [] server-side
|
||||
- [] client-side
|
||||
- [] not sure
|
||||
|
||||
**What browser are you using? (Client-side issues only)**
|
||||
<details>
|
||||
|
||||
**What operating system are you using? (Client-side issues only)**
|
||||
### Instance <!-- What instance of firefish are you using? -->
|
||||
|
||||
**How do you deploy Firefish on your server? (Server-side issues only)**
|
||||
### What browser are you using? (client-side issues only)
|
||||
|
||||
**What operating system are you using? (Server-side issues only)**
|
||||
### What operating system are you using? (client-side issues only)
|
||||
|
||||
**Relevant log output** _(Please copy and paste any relevant log output. You can find your log by inspecting the page, and going to the "console" tab. This will be automatically formatted into code, so no need for backticks.)_
|
||||
### How do you deploy Firefish on your server? (server-side issues only)
|
||||
|
||||
**Contribution Guidelines**
|
||||
### What operating system are you using? (Server-side issues only)
|
||||
|
||||
### Relevant log output <!-- Please copy and paste any relevant log output. You can find your log by inspecting the page, and going to the "console" tab. -->
|
||||
|
||||
</details>
|
||||
|
||||
## Contribution Guidelines
|
||||
By submitting this issue, you agree to follow our [Contribution Guidelines](https://firefish.dev/firefish/firefish/-/blob/develop/CONTRIBUTING.md)
|
||||
- [ ] I agree to follow this project's Contribution Guidelines
|
||||
- [ ] I have searched the issue tracker for similar issues, and this is not a duplicate.
|
||||
|
||||
**Are you willing to fix this bug?** (optional)
|
||||
## Are you willing to fix this bug? (optional)
|
||||
- [ ] Yes. I will fix this bug and open a merge request if the change is agreed upon.
|
||||
|
|
|
@ -3,18 +3,18 @@
|
|||
🔒 Found a security vulnerability? [Please disclose it responsibly.](https://firefish.dev/firefish/firefish/-/blob/develop/SECURITY.md)
|
||||
🤝 By submitting this feature request, you agree to follow our [Contribution Guidelines.](https://firefish.dev/firefish/firefish/-/blob/develop/CONTRIBUTING.md) -->
|
||||
|
||||
**What feature would you like implemented?** _(Please give us a brief description of what you'd like.)_
|
||||
## What feature would you like implemented? <!-- Please give us a brief description of what you'd like. -->
|
||||
|
||||
**Why should we add this feature?** _(Please give us a brief description of why your feature is important.)_
|
||||
## Why should we add this feature? <!-- Please give us a brief description of why your feature is important. -->
|
||||
|
||||
**Version** _(What version of firefish is your instance running? You can find this by clicking your instance's logo at the bottom left and then clicking instance information.)_
|
||||
## Version <!-- What version of firefish is your instance running? You can find this by clicking your instance's logo at the bottom left and then clicking instance information. -->
|
||||
|
||||
**Instance** _(What instance of firefish are you using?)_
|
||||
## Instance <!-- What instance of firefish are you using? -->
|
||||
|
||||
**Contribution Guidelines**
|
||||
## Contribution Guidelines
|
||||
By submitting this issue, you agree to follow our [Contribution Guidelines](https://firefish.dev/firefish/firefish/-/blob/develop/CONTRIBUTING.md)
|
||||
- [ ] I agree to follow this project's Contribution Guidelines
|
||||
- [ ] I have searched the issue tracker for similar requests, and this is not a duplicate.
|
||||
|
||||
**Are you willing to implement this feature?** (optional)
|
||||
## Are you willing to implement this feature? (optional)
|
||||
- [ ] Yes. I will implement this feature and open a merge request if the change is agreed upon.
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
<!-- Thanks for taking the time to make Firefish better! It's not required, but please consider using [Conventional Commits](https://www.conventionalcommits.org/en/v1.0.0/) when making your commits. If you use VSCode, please use the [Conventional Commits extension](https://marketplace.visualstudio.com/items?itemName=vivaxy.vscode-conventional-commits). -->
|
||||
|
||||
**What does this PR do?** _(Please give us a brief description of what this PR does.)_
|
||||
## What does this PR do? <!-- Please give us a brief description of what this PR does. -->
|
||||
|
||||
**Contribution Guidelines**
|
||||
## Contribution Guidelines
|
||||
By submitting this merge request, you agree to follow our [Contribution Guidelines](https://firefish.dev/firefish/firefish/-/blob/develop/CONTRIBUTING.md)
|
||||
- [ ] This change is reviewed in an issue / This is a minor bug fix
|
||||
- [ ] I agree to follow this project's Contribution Guidelines
|
||||
|
|
3
.vscode/extensions.json
vendored
3
.vscode/extensions.json
vendored
|
@ -12,6 +12,7 @@
|
|||
"esbenp.prettier-vscode",
|
||||
"redhat.vscode-yaml",
|
||||
"yoavbls.pretty-ts-errors",
|
||||
"biomejs.biome"
|
||||
"biomejs.biome",
|
||||
"rust-lang.rust-analyzer"
|
||||
]
|
||||
}
|
||||
|
|
207
Cargo.lock
generated
207
Cargo.lock
generated
|
@ -59,9 +59,9 @@ checksum = "250f629c0161ad8107cf89319e990051fae62832fd343083bea452d93e2205fd"
|
|||
|
||||
[[package]]
|
||||
name = "allocator-api2"
|
||||
version = "0.2.16"
|
||||
version = "0.2.18"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0942ffc6dcaadf03badf6e6a2d0228460359d5e34b57ccdc720b7382dfbd5ec5"
|
||||
checksum = "5c6cb57a04249c6480766f7f7cef5467412af1490f8d1e243141daddada3264f"
|
||||
|
||||
[[package]]
|
||||
name = "android-tzdata"
|
||||
|
@ -132,6 +132,18 @@ version = "1.0.82"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f538837af36e6f6a9be0faa67f9a314f8119e4e4b5867c6ab40ed60360142519"
|
||||
|
||||
[[package]]
|
||||
name = "argon2"
|
||||
version = "0.5.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3c3610892ee6e0cbce8ae2700349fcf8f98adb0dbfbee85aec3c9179d29cc072"
|
||||
dependencies = [
|
||||
"base64ct",
|
||||
"blake2",
|
||||
"cpufeatures",
|
||||
"password-hash",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "arrayvec"
|
||||
version = "0.7.4"
|
||||
|
@ -190,11 +202,14 @@ checksum = "f1fdabc7756949593fe60f30ec81974b613357de856987752631dea1e3394c80"
|
|||
name = "backend-rs"
|
||||
version = "0.0.0"
|
||||
dependencies = [
|
||||
"argon2",
|
||||
"async-trait",
|
||||
"basen",
|
||||
"bcrypt",
|
||||
"cfg-if",
|
||||
"chrono",
|
||||
"cuid2",
|
||||
"emojis",
|
||||
"idna",
|
||||
"jsonschema",
|
||||
"macro_rs",
|
||||
|
@ -238,6 +253,12 @@ version = "0.21.7"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9d297deb1925b89f2ccc13d7635fa0714f12c87adce1c75356b39ca9b7178567"
|
||||
|
||||
[[package]]
|
||||
name = "base64"
|
||||
version = "0.22.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9475866fec1451be56a3c2400fd081ff546538961565ccb5b7142cbd22bc7a51"
|
||||
|
||||
[[package]]
|
||||
name = "base64ct"
|
||||
version = "1.6.0"
|
||||
|
@ -250,6 +271,19 @@ version = "0.1.0"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1dbe4bb73fd931c4d1aaf53b35d1286c8a948ad00ec92c8e3c856f15fd027f43"
|
||||
|
||||
[[package]]
|
||||
name = "bcrypt"
|
||||
version = "0.15.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e65938ed058ef47d92cf8b346cc76ef48984572ade631927e9937b5ffc7662c7"
|
||||
dependencies = [
|
||||
"base64 0.22.0",
|
||||
"blowfish",
|
||||
"getrandom",
|
||||
"subtle",
|
||||
"zeroize",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "bigdecimal"
|
||||
version = "0.3.1"
|
||||
|
@ -303,6 +337,15 @@ dependencies = [
|
|||
"wyz",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "blake2"
|
||||
version = "0.10.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "46502ad458c9a52b69d4d4d32775c788b7a1b85e8bc9d482d92250fc0e3f8efe"
|
||||
dependencies = [
|
||||
"digest",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "block-buffer"
|
||||
version = "0.10.4"
|
||||
|
@ -312,6 +355,16 @@ dependencies = [
|
|||
"generic-array",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "blowfish"
|
||||
version = "0.9.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e412e2cd0f2b2d93e02543ceae7917b3c70331573df19ee046bcbc35e45e87d7"
|
||||
dependencies = [
|
||||
"byteorder",
|
||||
"cipher",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "borsh"
|
||||
version = "1.4.0"
|
||||
|
@ -384,9 +437,9 @@ checksum = "514de17de45fdb8dc022b1a7975556c53c86f9f0aa5f534b98977b171857c2c9"
|
|||
|
||||
[[package]]
|
||||
name = "cc"
|
||||
version = "1.0.92"
|
||||
version = "1.0.94"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2678b2e3449475e95b0aa6f9b506a28e61b3dc8996592b983695e8ebb58a8b41"
|
||||
checksum = "17f6e324229dc011159fcc089755d1e2e216a90d43a7dea6853ca740b84f35e7"
|
||||
|
||||
[[package]]
|
||||
name = "cfg-if"
|
||||
|
@ -412,7 +465,17 @@ dependencies = [
|
|||
"num-traits",
|
||||
"serde",
|
||||
"wasm-bindgen",
|
||||
"windows-targets 0.52.4",
|
||||
"windows-targets 0.52.5",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "cipher"
|
||||
version = "0.4.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "773f3b9af64447d2ce9850330c473515014aa235e6a783b02db81ff39e4a3dad"
|
||||
dependencies = [
|
||||
"crypto-common",
|
||||
"inout",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
@ -633,13 +696,22 @@ checksum = "0d6ef0072f8a535281e4876be788938b528e9a1d43900b82c2569af7da799125"
|
|||
|
||||
[[package]]
|
||||
name = "either"
|
||||
version = "1.10.0"
|
||||
version = "1.11.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "11157ac094ffbdde99aa67b23417ebdd801842852b500e395a45a9c0aac03e4a"
|
||||
checksum = "a47c1c47d2f5964e29c61246e81db715514cd532db6b5116a25ea3c03d6780a2"
|
||||
dependencies = [
|
||||
"serde",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "emojis"
|
||||
version = "0.6.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "4ee61eb945bff65ee7d19d157d39c67c33290ff0742907413fd5eefd29edc979"
|
||||
dependencies = [
|
||||
"phf",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "encoding_rs"
|
||||
version = "0.8.34"
|
||||
|
@ -1075,6 +1147,15 @@ dependencies = [
|
|||
"syn 2.0.58",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "inout"
|
||||
version = "0.1.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a0c10553d664a4d0bcff9f4215d0aac67a639cc68ef660840afe309b807bc9f5"
|
||||
dependencies = [
|
||||
"generic-array",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "ipnet"
|
||||
version = "2.9.0"
|
||||
|
@ -1122,7 +1203,7 @@ checksum = "2a071f4f7efc9a9118dfb627a0a94ef247986e1ab8606a4c806ae2b3aa3b6978"
|
|||
dependencies = [
|
||||
"ahash 0.8.11",
|
||||
"anyhow",
|
||||
"base64",
|
||||
"base64 0.21.7",
|
||||
"bytecount",
|
||||
"clap",
|
||||
"fancy-regex",
|
||||
|
@ -1175,7 +1256,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|||
checksum = "0c2a198fb6b0eada2a8df47933734e6d35d350665a33a3593d7164fa52c75c19"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
"windows-targets 0.52.4",
|
||||
"windows-targets 0.52.5",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
@ -1296,9 +1377,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "napi-build"
|
||||
version = "2.1.2"
|
||||
version = "2.1.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2f9130fccc5f763cf2069b34a089a18f0d0883c66aceb81f2fad541a3d823c43"
|
||||
checksum = "e1c0f5d67ee408a4685b61f5ab7e58605c8ae3f2b4189f0127d804ff13d5560a"
|
||||
|
||||
[[package]]
|
||||
name = "napi-derive"
|
||||
|
@ -1350,9 +1431,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "num"
|
||||
version = "0.4.1"
|
||||
version = "0.4.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b05180d69e3da0e530ba2a1dae5110317e49e3b7f3d41be227dc5f92e49ee7af"
|
||||
checksum = "3135b08af27d103b0a51f2ae0f8632117b7b185ccf931445affa8df530576a41"
|
||||
dependencies = [
|
||||
"num-bigint",
|
||||
"num-complex",
|
||||
|
@ -1559,6 +1640,17 @@ dependencies = [
|
|||
"syn 2.0.58",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "password-hash"
|
||||
version = "0.5.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "346f04948ba92c43e8469c1ee6736c7563d71012b17d40745260fe106aac2166"
|
||||
dependencies = [
|
||||
"base64ct",
|
||||
"rand_core",
|
||||
"subtle",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "paste"
|
||||
version = "1.0.14"
|
||||
|
@ -1580,6 +1672,24 @@ version = "2.3.1"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e3148f5046208a5d56bcfc03053e3ca6334e51da8dfb19b6cdc8b306fae3283e"
|
||||
|
||||
[[package]]
|
||||
name = "phf"
|
||||
version = "0.11.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ade2d8b8f33c7333b51bcf0428d37e217e9f32192ae4772156f65063b8ce03dc"
|
||||
dependencies = [
|
||||
"phf_shared",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "phf_shared"
|
||||
version = "0.11.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "90fcb95eef784c2ac79119d1dd819e162b5da872ce6f3c3abe1e8ca1c082f72b"
|
||||
dependencies = [
|
||||
"siphasher",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "pin-project-lite"
|
||||
version = "0.2.14"
|
||||
|
@ -1801,7 +1911,7 @@ version = "0.11.27"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "dd67538700a17451e7cba03ac727fb961abb7607553461627b97de0b89cf4a62"
|
||||
dependencies = [
|
||||
"base64",
|
||||
"base64 0.21.7",
|
||||
"bytes",
|
||||
"encoding_rs",
|
||||
"futures-core",
|
||||
|
@ -1947,7 +2057,7 @@ version = "1.0.4"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1c74cae0a4cf6ccbbf5f359f08efdf8ee7e1dc532573bf0db71968cb56b1448c"
|
||||
dependencies = [
|
||||
"base64",
|
||||
"base64 0.21.7",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
@ -2231,6 +2341,12 @@ version = "0.1.4"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f27f6278552951f1f2b8cf9da965d10969b2efdea95a6ec47987ab46edfe263a"
|
||||
|
||||
[[package]]
|
||||
name = "siphasher"
|
||||
version = "0.3.11"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "38b58827f4464d87d377d175e90bf58eb00fd8716ff0a62f80356b5e61555d0d"
|
||||
|
||||
[[package]]
|
||||
name = "slab"
|
||||
version = "0.4.9"
|
||||
|
@ -2398,7 +2514,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|||
checksum = "1ed31390216d20e538e447a7a9b959e06ed9fc51c37b514b46eb758016ecd418"
|
||||
dependencies = [
|
||||
"atoi",
|
||||
"base64",
|
||||
"base64 0.21.7",
|
||||
"bigdecimal",
|
||||
"bitflags 2.5.0",
|
||||
"byteorder",
|
||||
|
@ -2445,7 +2561,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|||
checksum = "7c824eb80b894f926f89a0b9da0c7f435d27cdd35b8c655b114e58223918577e"
|
||||
dependencies = [
|
||||
"atoi",
|
||||
"base64",
|
||||
"base64 0.21.7",
|
||||
"bigdecimal",
|
||||
"bitflags 2.5.0",
|
||||
"byteorder",
|
||||
|
@ -3041,7 +3157,7 @@ version = "0.52.0"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "33ab640c8d7e35bf8ba19b884ba838ceb4fba93a4e8c65a9059d08afcfc683d9"
|
||||
dependencies = [
|
||||
"windows-targets 0.52.4",
|
||||
"windows-targets 0.52.5",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
@ -3059,7 +3175,7 @@ version = "0.52.0"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d"
|
||||
dependencies = [
|
||||
"windows-targets 0.52.4",
|
||||
"windows-targets 0.52.5",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
@ -3079,17 +3195,18 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "windows-targets"
|
||||
version = "0.52.4"
|
||||
version = "0.52.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7dd37b7e5ab9018759f893a1952c9420d060016fc19a472b4bb20d1bdd694d1b"
|
||||
checksum = "6f0713a46559409d202e70e28227288446bf7841d3211583a4b53e3f6d96e7eb"
|
||||
dependencies = [
|
||||
"windows_aarch64_gnullvm 0.52.4",
|
||||
"windows_aarch64_msvc 0.52.4",
|
||||
"windows_i686_gnu 0.52.4",
|
||||
"windows_i686_msvc 0.52.4",
|
||||
"windows_x86_64_gnu 0.52.4",
|
||||
"windows_x86_64_gnullvm 0.52.4",
|
||||
"windows_x86_64_msvc 0.52.4",
|
||||
"windows_aarch64_gnullvm 0.52.5",
|
||||
"windows_aarch64_msvc 0.52.5",
|
||||
"windows_i686_gnu 0.52.5",
|
||||
"windows_i686_gnullvm",
|
||||
"windows_i686_msvc 0.52.5",
|
||||
"windows_x86_64_gnu 0.52.5",
|
||||
"windows_x86_64_gnullvm 0.52.5",
|
||||
"windows_x86_64_msvc 0.52.5",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
@ -3100,9 +3217,9 @@ checksum = "2b38e32f0abccf9987a4e3079dfb67dcd799fb61361e53e2882c3cbaf0d905d8"
|
|||
|
||||
[[package]]
|
||||
name = "windows_aarch64_gnullvm"
|
||||
version = "0.52.4"
|
||||
version = "0.52.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "bcf46cf4c365c6f2d1cc93ce535f2c8b244591df96ceee75d8e83deb70a9cac9"
|
||||
checksum = "7088eed71e8b8dda258ecc8bac5fb1153c5cffaf2578fc8ff5d61e23578d3263"
|
||||
|
||||
[[package]]
|
||||
name = "windows_aarch64_msvc"
|
||||
|
@ -3112,9 +3229,9 @@ checksum = "dc35310971f3b2dbbf3f0690a219f40e2d9afcf64f9ab7cc1be722937c26b4bc"
|
|||
|
||||
[[package]]
|
||||
name = "windows_aarch64_msvc"
|
||||
version = "0.52.4"
|
||||
version = "0.52.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "da9f259dd3bcf6990b55bffd094c4f7235817ba4ceebde8e6d11cd0c5633b675"
|
||||
checksum = "9985fd1504e250c615ca5f281c3f7a6da76213ebd5ccc9561496568a2752afb6"
|
||||
|
||||
[[package]]
|
||||
name = "windows_i686_gnu"
|
||||
|
@ -3124,9 +3241,15 @@ checksum = "a75915e7def60c94dcef72200b9a8e58e5091744960da64ec734a6c6e9b3743e"
|
|||
|
||||
[[package]]
|
||||
name = "windows_i686_gnu"
|
||||
version = "0.52.4"
|
||||
version = "0.52.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b474d8268f99e0995f25b9f095bc7434632601028cf86590aea5c8a5cb7801d3"
|
||||
checksum = "88ba073cf16d5372720ec942a8ccbf61626074c6d4dd2e745299726ce8b89670"
|
||||
|
||||
[[package]]
|
||||
name = "windows_i686_gnullvm"
|
||||
version = "0.52.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "87f4261229030a858f36b459e748ae97545d6f1ec60e5e0d6a3d32e0dc232ee9"
|
||||
|
||||
[[package]]
|
||||
name = "windows_i686_msvc"
|
||||
|
@ -3136,9 +3259,9 @@ checksum = "8f55c233f70c4b27f66c523580f78f1004e8b5a8b659e05a4eb49d4166cca406"
|
|||
|
||||
[[package]]
|
||||
name = "windows_i686_msvc"
|
||||
version = "0.52.4"
|
||||
version = "0.52.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1515e9a29e5bed743cb4415a9ecf5dfca648ce85ee42e15873c3cd8610ff8e02"
|
||||
checksum = "db3c2bf3d13d5b658be73463284eaf12830ac9a26a90c717b7f771dfe97487bf"
|
||||
|
||||
[[package]]
|
||||
name = "windows_x86_64_gnu"
|
||||
|
@ -3148,9 +3271,9 @@ checksum = "53d40abd2583d23e4718fddf1ebec84dbff8381c07cae67ff7768bbf19c6718e"
|
|||
|
||||
[[package]]
|
||||
name = "windows_x86_64_gnu"
|
||||
version = "0.52.4"
|
||||
version = "0.52.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5eee091590e89cc02ad514ffe3ead9eb6b660aedca2183455434b93546371a03"
|
||||
checksum = "4e4246f76bdeff09eb48875a0fd3e2af6aada79d409d33011886d3e1581517d9"
|
||||
|
||||
[[package]]
|
||||
name = "windows_x86_64_gnullvm"
|
||||
|
@ -3160,9 +3283,9 @@ checksum = "0b7b52767868a23d5bab768e390dc5f5c55825b6d30b86c844ff2dc7414044cc"
|
|||
|
||||
[[package]]
|
||||
name = "windows_x86_64_gnullvm"
|
||||
version = "0.52.4"
|
||||
version = "0.52.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "77ca79f2451b49fa9e2af39f0747fe999fcda4f5e241b2898624dca97a1f2177"
|
||||
checksum = "852298e482cd67c356ddd9570386e2862b5673c85bd5f88df9ab6802b334c596"
|
||||
|
||||
[[package]]
|
||||
name = "windows_x86_64_msvc"
|
||||
|
@ -3172,9 +3295,9 @@ checksum = "ed94fce61571a4006852b7389a063ab983c02eb1bb37b47f8272ce92d06d9538"
|
|||
|
||||
[[package]]
|
||||
name = "windows_x86_64_msvc"
|
||||
version = "0.52.4"
|
||||
version = "0.52.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "32b752e52a2da0ddfbdbcc6fceadfeede4c939ed16d13e648833a61dfb611ed8"
|
||||
checksum = "bec47e5bfd1bff0eeaf6d8b485cc1074891a197ab4225d504cb7a1ab88b02bf0"
|
||||
|
||||
[[package]]
|
||||
name = "winnow"
|
||||
|
|
|
@ -7,14 +7,17 @@ macro_rs = { path = "packages/macro-rs" }
|
|||
|
||||
napi = { version = "2.16.2", default-features = false }
|
||||
napi-derive = "2.16.2"
|
||||
napi-build = "2.1.2"
|
||||
napi-build = "2.1.3"
|
||||
|
||||
argon2 = "0.5.3"
|
||||
async-trait = "0.1.80"
|
||||
basen = "0.1.0"
|
||||
bcrypt = "0.15.1"
|
||||
cfg-if = "1.0.0"
|
||||
chrono = "0.4.37"
|
||||
convert_case = "0.6.0"
|
||||
cuid2 = "0.1.2"
|
||||
emojis = "0.6.1"
|
||||
idna = "0.5.0"
|
||||
jsonschema = "0.17.1"
|
||||
once_cell = "1.19.0"
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
Breaking changes are indicated by the :warning: icon.
|
||||
|
||||
## Unreleased
|
||||
## v20240413
|
||||
|
||||
- :warning: Removed `patrons` endpoint.
|
||||
|
||||
|
|
|
@ -5,9 +5,12 @@ Critical security updates are indicated by the :warning: icon.
|
|||
- Server administrators should check [notice-for-admins.md](./notice-for-admins.md) as well.
|
||||
- Third-party client/bot developers may want to check [api-change.md](./api-change.md) as well.
|
||||
|
||||
## Unreleased
|
||||
## [v20240413](https://firefish.dev/firefish/firefish/-/merge_requests/10741/commits)
|
||||
|
||||
- Add "Media" tab to user page
|
||||
- Improve federation and rendering of mathematical expressions
|
||||
- Remove donor information from the web client
|
||||
- See also: https://info.firefish.dev/notes/9s1n283sb10rh869
|
||||
- Fix bugs
|
||||
|
||||
## [v20240405](https://firefish.dev/firefish/firefish/-/merge_requests/10733/commits)
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
You can skip intermediate versions when upgrading from an old version, but please read the notices and follow the instructions for each intermediate version before [upgrading](./upgrade.md).
|
||||
|
||||
## Unreleased
|
||||
## v20240413
|
||||
|
||||
### For all users
|
||||
|
||||
|
|
|
@ -2318,3 +2318,4 @@ markLocalFilesNsfwByDefaultDescription: Indépendamment de ce réglage, les util
|
|||
peuvent supprimer le drapeau « sensible » (NSFW) eux-mêmes. Les fichiers existants
|
||||
ne sont pas affectés.
|
||||
noteEditHistory: Historique des publications
|
||||
media: Multimédia
|
||||
|
|
10
package.json
10
package.json
|
@ -1,11 +1,11 @@
|
|||
{
|
||||
"name": "firefish",
|
||||
"version": "20240405",
|
||||
"version": "20240413",
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "https://firefish.dev/firefish/firefish.git"
|
||||
},
|
||||
"packageManager": "pnpm@8.15.6",
|
||||
"packageManager": "pnpm@8.15.7",
|
||||
"private": true,
|
||||
"scripts": {
|
||||
"rebuild": "pnpm run clean && pnpm run build",
|
||||
|
@ -36,11 +36,11 @@
|
|||
"clean-all": "pnpm run clean && pnpm run clean-cargo && pnpm run clean-npm"
|
||||
},
|
||||
"dependencies": {
|
||||
"js-yaml": "4.1.0",
|
||||
"gulp": "4.0.2",
|
||||
"gulp-cssnano": "2.1.3",
|
||||
"gulp-replace": "1.1.4",
|
||||
"gulp-terser": "2.1.0"
|
||||
"gulp-terser": "2.1.0",
|
||||
"js-yaml": "4.1.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@biomejs/biome": "1.6.4",
|
||||
|
@ -50,7 +50,7 @@
|
|||
"@biomejs/cli-linux-x64": "^1.6.4",
|
||||
"@types/node": "20.12.7",
|
||||
"execa": "8.0.1",
|
||||
"pnpm": "8.15.6",
|
||||
"pnpm": "8.15.7",
|
||||
"typescript": "5.4.5"
|
||||
}
|
||||
}
|
||||
|
|
|
@ -4,6 +4,7 @@ This directory contains all of the packages Firefish uses.
|
|||
|
||||
- `backend`: Main backend code written in TypeScript for NodeJS
|
||||
- `backend-rs`: Backend code written in Rust, bound to NodeJS by [NAPI-RS](https://napi.rs/)
|
||||
- `macro-rs`: Procedural macros for backend-rs
|
||||
- `client`: Web interface written in Vue3 and TypeScript
|
||||
- `sw`: Web [Service Worker](https://developer.mozilla.org/en-US/docs/Web/API/Service_Worker_API) written in TypeScript
|
||||
- `firefish-js`: TypeScript SDK for both backend and client
|
||||
|
|
|
@ -17,11 +17,14 @@ macro_rs = { workspace = true }
|
|||
napi = { workspace = true, optional = true, default-features = false, features = ["napi9", "tokio_rt", "chrono_date", "serde-json"] }
|
||||
napi-derive = { workspace = true, optional = true }
|
||||
|
||||
argon2 = { workspace = true, features = ["std"] }
|
||||
async-trait = { workspace = true }
|
||||
basen = { workspace = true }
|
||||
bcrypt = { workspace = true }
|
||||
cfg-if = { workspace = true }
|
||||
chrono = { workspace = true }
|
||||
cuid2 = { workspace = true }
|
||||
emojis = { workspace = true }
|
||||
idna = { workspace = true }
|
||||
jsonschema = { workspace = true }
|
||||
once_cell = { workspace = true }
|
||||
|
|
39
packages/backend-rs/index.d.ts
vendored
39
packages/backend-rs/index.d.ts
vendored
|
@ -3,6 +3,16 @@
|
|||
|
||||
/* auto-generated by NAPI-RS */
|
||||
|
||||
export interface EnvConfig {
|
||||
onlyQueue: boolean
|
||||
onlyServer: boolean
|
||||
noDaemons: boolean
|
||||
disableClustering: boolean
|
||||
verbose: boolean
|
||||
withLogTime: boolean
|
||||
slow: boolean
|
||||
}
|
||||
export function readEnvironmentConfig(): EnvConfig
|
||||
export interface ServerConfig {
|
||||
url: string
|
||||
port: number
|
||||
|
@ -132,9 +142,38 @@ export function isSelfHost(host?: string | undefined | null): boolean
|
|||
export function isSameOrigin(uri: string): boolean
|
||||
export function extractHost(uri: string): string
|
||||
export function toPuny(host: string): string
|
||||
export function isUnicodeEmoji(s: string): boolean
|
||||
export function sqlLikeEscape(src: string): string
|
||||
export function safeForSql(src: string): boolean
|
||||
/** Convert milliseconds to a human readable string */
|
||||
export function formatMilliseconds(milliseconds: number): string
|
||||
export function toMastodonId(firefishId: string): string | null
|
||||
export function fromMastodonId(mastodonId: string): string | null
|
||||
export function fetchMeta(useCache: boolean): Promise<Meta>
|
||||
export interface PugArgs {
|
||||
img: string | null
|
||||
title: string
|
||||
instanceName: string
|
||||
desc: string | null
|
||||
icon: string | null
|
||||
splashIcon: string | null
|
||||
themeColor: string | null
|
||||
randomMotd: string
|
||||
privateMode: boolean | null
|
||||
}
|
||||
export function metaToPugArgs(meta: Meta): PugArgs
|
||||
export function nyaify(text: string, lang?: string | undefined | null): string
|
||||
export function hashPassword(password: string): string
|
||||
export function verifyPassword(password: string, hash: string): boolean
|
||||
export function isOldPasswordAlgorithm(hash: string): boolean
|
||||
export interface DecodedReaction {
|
||||
reaction: string
|
||||
name: string | null
|
||||
host: string | null
|
||||
}
|
||||
export function decodeReaction(reaction: string): DecodedReaction
|
||||
export function countReactions(reactions: Record<string, number>): Record<string, number>
|
||||
export function toDbReaction(reaction?: string | undefined | null, host?: string | undefined | null): Promise<string>
|
||||
export interface AbuseUserReport {
|
||||
id: string
|
||||
createdAt: Date
|
||||
|
|
|
@ -310,8 +310,9 @@ if (!nativeBinding) {
|
|||
throw new Error(`Failed to load native binding`)
|
||||
}
|
||||
|
||||
const { readServerConfig, stringToAcct, acctToString, checkWordMute, getFullApAccount, isSelfHost, isSameOrigin, extractHost, toPuny, toMastodonId, fromMastodonId, nyaify, AntennaSrcEnum, MutedNoteReasonEnum, NoteVisibilityEnum, NotificationTypeEnum, PageVisibilityEnum, PollNotevisibilityEnum, RelayStatusEnum, UserEmojimodpermEnum, UserProfileFfvisibilityEnum, UserProfileMutingnotificationtypesEnum, initIdGenerator, getTimestamp, genId, secureRndstr } = nativeBinding
|
||||
const { readEnvironmentConfig, readServerConfig, stringToAcct, acctToString, checkWordMute, getFullApAccount, isSelfHost, isSameOrigin, extractHost, toPuny, isUnicodeEmoji, sqlLikeEscape, safeForSql, formatMilliseconds, toMastodonId, fromMastodonId, fetchMeta, metaToPugArgs, nyaify, hashPassword, verifyPassword, isOldPasswordAlgorithm, decodeReaction, countReactions, toDbReaction, AntennaSrcEnum, MutedNoteReasonEnum, NoteVisibilityEnum, NotificationTypeEnum, PageVisibilityEnum, PollNotevisibilityEnum, RelayStatusEnum, UserEmojimodpermEnum, UserProfileFfvisibilityEnum, UserProfileMutingnotificationtypesEnum, initIdGenerator, getTimestamp, genId, secureRndstr } = nativeBinding
|
||||
|
||||
module.exports.readEnvironmentConfig = readEnvironmentConfig
|
||||
module.exports.readServerConfig = readServerConfig
|
||||
module.exports.stringToAcct = stringToAcct
|
||||
module.exports.acctToString = acctToString
|
||||
|
@ -321,9 +322,21 @@ module.exports.isSelfHost = isSelfHost
|
|||
module.exports.isSameOrigin = isSameOrigin
|
||||
module.exports.extractHost = extractHost
|
||||
module.exports.toPuny = toPuny
|
||||
module.exports.isUnicodeEmoji = isUnicodeEmoji
|
||||
module.exports.sqlLikeEscape = sqlLikeEscape
|
||||
module.exports.safeForSql = safeForSql
|
||||
module.exports.formatMilliseconds = formatMilliseconds
|
||||
module.exports.toMastodonId = toMastodonId
|
||||
module.exports.fromMastodonId = fromMastodonId
|
||||
module.exports.fetchMeta = fetchMeta
|
||||
module.exports.metaToPugArgs = metaToPugArgs
|
||||
module.exports.nyaify = nyaify
|
||||
module.exports.hashPassword = hashPassword
|
||||
module.exports.verifyPassword = verifyPassword
|
||||
module.exports.isOldPasswordAlgorithm = isOldPasswordAlgorithm
|
||||
module.exports.decodeReaction = decodeReaction
|
||||
module.exports.countReactions = countReactions
|
||||
module.exports.toDbReaction = toDbReaction
|
||||
module.exports.AntennaSrcEnum = AntennaSrcEnum
|
||||
module.exports.MutedNoteReasonEnum = MutedNoteReasonEnum
|
||||
module.exports.NoteVisibilityEnum = NoteVisibilityEnum
|
||||
|
|
27
packages/backend-rs/src/config/environment.rs
Normal file
27
packages/backend-rs/src/config/environment.rs
Normal file
|
@ -0,0 +1,27 @@
|
|||
// FIXME: Are these options used?
|
||||
#[crate::export(object)]
|
||||
pub struct EnvConfig {
|
||||
pub only_queue: bool,
|
||||
pub only_server: bool,
|
||||
pub no_daemons: bool,
|
||||
pub disable_clustering: bool,
|
||||
pub verbose: bool,
|
||||
pub with_log_time: bool,
|
||||
pub slow: bool,
|
||||
}
|
||||
|
||||
#[crate::export]
|
||||
pub fn read_environment_config() -> EnvConfig {
|
||||
let node_env = std::env::var("NODE_ENV").unwrap_or_default().to_lowercase();
|
||||
let is_testing = node_env == "test";
|
||||
|
||||
EnvConfig {
|
||||
only_queue: std::env::var("MK_ONLY_QUEUE").is_ok(),
|
||||
only_server: std::env::var("MK_ONLY_SERVER").is_ok(),
|
||||
no_daemons: is_testing || std::env::var("MK_NO_DAEMONS").is_ok(),
|
||||
disable_clustering: is_testing || std::env::var("MK_DISABLE_CLUSTERING").is_ok(),
|
||||
verbose: std::env::var("MK_VERBOSE").is_ok(),
|
||||
with_log_time: std::env::var("MK_WITH_LOG_TIME").is_ok(),
|
||||
slow: std::env::var("MK_SLOW").is_ok(),
|
||||
}
|
||||
}
|
|
@ -1 +1,2 @@
|
|||
pub mod environment;
|
||||
pub mod server;
|
||||
|
|
31
packages/backend-rs/src/misc/emoji.rs
Normal file
31
packages/backend-rs/src/misc/emoji.rs
Normal file
|
@ -0,0 +1,31 @@
|
|||
#[inline]
|
||||
#[crate::export]
|
||||
pub fn is_unicode_emoji(s: &str) -> bool {
|
||||
emojis::get(s).is_some()
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod unit_test {
|
||||
use super::is_unicode_emoji;
|
||||
|
||||
#[test]
|
||||
fn test_unicode_emoji_check() {
|
||||
assert!(is_unicode_emoji("⭐"));
|
||||
assert!(is_unicode_emoji("👍"));
|
||||
assert!(is_unicode_emoji("❤"));
|
||||
assert!(is_unicode_emoji("♥️"));
|
||||
assert!(is_unicode_emoji("❤️"));
|
||||
assert!(is_unicode_emoji("💙"));
|
||||
assert!(is_unicode_emoji("🩷"));
|
||||
assert!(is_unicode_emoji("🖖🏿"));
|
||||
assert!(is_unicode_emoji("🏃➡️"));
|
||||
assert!(is_unicode_emoji("👩❤️👨"));
|
||||
assert!(is_unicode_emoji("👩👦👦"));
|
||||
assert!(is_unicode_emoji("🏳️🌈"));
|
||||
|
||||
assert!(!is_unicode_emoji("⭐⭐"));
|
||||
assert!(!is_unicode_emoji("x"));
|
||||
assert!(!is_unicode_emoji("\t"));
|
||||
assert!(!is_unicode_emoji(":meow_aww:"));
|
||||
}
|
||||
}
|
36
packages/backend-rs/src/misc/escape_sql.rs
Normal file
36
packages/backend-rs/src/misc/escape_sql.rs
Normal file
|
@ -0,0 +1,36 @@
|
|||
#[crate::export]
|
||||
pub fn sql_like_escape(src: &str) -> String {
|
||||
src.replace('%', r"\%").replace('_', r"\_")
|
||||
}
|
||||
|
||||
#[crate::export]
|
||||
pub fn safe_for_sql(src: &str) -> bool {
|
||||
!src.contains([
|
||||
'\0', '\x08', '\x09', '\x1a', '\n', '\r', '"', '\'', '\\', '%',
|
||||
])
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod unit_test {
|
||||
use super::{safe_for_sql, sql_like_escape};
|
||||
use pretty_assertions::assert_eq;
|
||||
|
||||
#[test]
|
||||
fn sql_like_escape_test() {
|
||||
assert_eq!(sql_like_escape(""), "");
|
||||
assert_eq!(sql_like_escape("abc"), "abc");
|
||||
assert_eq!(sql_like_escape("a%bc"), r"a\%bc");
|
||||
assert_eq!(sql_like_escape("a呼%吸bc"), r"a呼\%吸bc");
|
||||
assert_eq!(sql_like_escape("a呼%吸b%_c"), r"a呼\%吸b\%\_c");
|
||||
assert_eq!(sql_like_escape("_اللغة العربية"), r"\_اللغة العربية");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn safe_for_sql_test() {
|
||||
assert!(safe_for_sql("123"));
|
||||
assert!(safe_for_sql("人間"));
|
||||
assert!(!safe_for_sql("人間\x09"));
|
||||
assert!(!safe_for_sql("abc\ndef"));
|
||||
assert!(!safe_for_sql("%something%"));
|
||||
}
|
||||
}
|
46
packages/backend-rs/src/misc/format_milliseconds.rs
Normal file
46
packages/backend-rs/src/misc/format_milliseconds.rs
Normal file
|
@ -0,0 +1,46 @@
|
|||
/// Convert milliseconds to a human readable string
|
||||
#[crate::export]
|
||||
pub fn format_milliseconds(milliseconds: u32) -> String {
|
||||
let mut seconds = milliseconds / 1000;
|
||||
let mut minutes = seconds / 60;
|
||||
let mut hours = minutes / 60;
|
||||
let days = hours / 24;
|
||||
|
||||
seconds %= 60;
|
||||
minutes %= 60;
|
||||
hours %= 24;
|
||||
|
||||
let mut buf: Vec<String> = vec![];
|
||||
|
||||
if days > 0 {
|
||||
buf.push(format!("{} day(s)", days));
|
||||
}
|
||||
if hours > 0 {
|
||||
buf.push(format!("{} hour(s)", hours));
|
||||
}
|
||||
if minutes > 0 {
|
||||
buf.push(format!("{} minute(s)", minutes));
|
||||
}
|
||||
if seconds > 0 {
|
||||
buf.push(format!("{} second(s)", seconds));
|
||||
}
|
||||
|
||||
buf.join(", ")
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod unit_test {
|
||||
use super::format_milliseconds;
|
||||
use pretty_assertions::assert_eq;
|
||||
|
||||
#[test]
|
||||
fn format_milliseconds_test() {
|
||||
assert_eq!(format_milliseconds(1000), "1 second(s)");
|
||||
assert_eq!(format_milliseconds(1387938), "23 minute(s), 7 second(s)");
|
||||
assert_eq!(format_milliseconds(34200457), "9 hour(s), 30 minute(s)");
|
||||
assert_eq!(
|
||||
format_milliseconds(998244353),
|
||||
"11 day(s), 13 hour(s), 17 minute(s), 24 second(s)"
|
||||
);
|
||||
}
|
||||
}
|
83
packages/backend-rs/src/misc/meta.rs
Normal file
83
packages/backend-rs/src/misc/meta.rs
Normal file
|
@ -0,0 +1,83 @@
|
|||
use crate::database::db_conn;
|
||||
use crate::model::entity::meta;
|
||||
use rand::prelude::*;
|
||||
use sea_orm::{prelude::*, ActiveValue};
|
||||
use std::sync::Mutex;
|
||||
|
||||
type Meta = meta::Model;
|
||||
|
||||
static CACHE: Mutex<Option<Meta>> = Mutex::new(None);
|
||||
fn update_cache(meta: &Meta) {
|
||||
let _ = CACHE.lock().map(|mut cache| *cache = Some(meta.clone()));
|
||||
}
|
||||
|
||||
#[crate::export]
|
||||
pub async fn fetch_meta(use_cache: bool) -> Result<Meta, DbErr> {
|
||||
// try using cache
|
||||
if use_cache {
|
||||
if let Some(cache) = CACHE.lock().ok().and_then(|cache| cache.clone()) {
|
||||
return Ok(cache);
|
||||
}
|
||||
}
|
||||
|
||||
// try fetching from db
|
||||
let db = db_conn().await?;
|
||||
let meta = meta::Entity::find().one(db).await?;
|
||||
if let Some(meta) = meta {
|
||||
update_cache(&meta);
|
||||
return Ok(meta);
|
||||
}
|
||||
|
||||
// create a new meta object and insert into db
|
||||
let meta = meta::Entity::insert(meta::ActiveModel {
|
||||
id: ActiveValue::Set("x".to_owned()),
|
||||
..Default::default()
|
||||
})
|
||||
.exec_with_returning(db)
|
||||
.await?;
|
||||
update_cache(&meta);
|
||||
Ok(meta)
|
||||
}
|
||||
|
||||
#[crate::export(object)]
|
||||
pub struct PugArgs {
|
||||
pub img: Option<String>,
|
||||
pub title: String,
|
||||
pub instance_name: String,
|
||||
pub desc: Option<String>,
|
||||
pub icon: Option<String>,
|
||||
pub splash_icon: Option<String>,
|
||||
pub theme_color: Option<String>,
|
||||
pub random_motd: String,
|
||||
pub private_mode: Option<bool>,
|
||||
}
|
||||
|
||||
#[crate::export]
|
||||
pub fn meta_to_pug_args(meta: Meta) -> PugArgs {
|
||||
let mut rng = rand::thread_rng();
|
||||
|
||||
let splash_icon = meta
|
||||
.custom_splash_icons
|
||||
.choose(&mut rng)
|
||||
.map(|s| s.to_owned())
|
||||
.or_else(|| meta.icon_url.to_owned());
|
||||
|
||||
let random_motd = meta
|
||||
.custom_motd
|
||||
.choose(&mut rng)
|
||||
.map(|s| s.to_owned())
|
||||
.unwrap_or_else(|| "Loading...".to_owned());
|
||||
|
||||
let name = meta.name.unwrap_or_else(|| "Firefish".to_owned());
|
||||
PugArgs {
|
||||
img: meta.banner_url,
|
||||
title: name.clone(),
|
||||
instance_name: name.clone(),
|
||||
desc: meta.description,
|
||||
icon: meta.icon_url,
|
||||
splash_icon,
|
||||
theme_color: meta.theme_color,
|
||||
random_motd,
|
||||
private_mode: meta.private_mode,
|
||||
}
|
||||
}
|
|
@ -1,5 +1,11 @@
|
|||
pub mod acct;
|
||||
pub mod check_word_mute;
|
||||
pub mod convert_host;
|
||||
pub mod emoji;
|
||||
pub mod escape_sql;
|
||||
pub mod format_milliseconds;
|
||||
pub mod mastodon_id;
|
||||
pub mod meta;
|
||||
pub mod nyaify;
|
||||
pub mod password;
|
||||
pub mod reaction;
|
||||
|
|
69
packages/backend-rs/src/misc/password.rs
Normal file
69
packages/backend-rs/src/misc/password.rs
Normal file
|
@ -0,0 +1,69 @@
|
|||
use argon2::{
|
||||
password_hash,
|
||||
password_hash::{rand_core::OsRng, PasswordHash, PasswordHasher, PasswordVerifier, SaltString},
|
||||
Argon2,
|
||||
};
|
||||
|
||||
#[crate::export]
|
||||
pub fn hash_password(password: &str) -> Result<String, password_hash::errors::Error> {
|
||||
let salt = SaltString::generate(&mut OsRng);
|
||||
Ok(Argon2::default()
|
||||
.hash_password(password.as_bytes(), &salt)?
|
||||
.to_string())
|
||||
}
|
||||
|
||||
#[derive(thiserror::Error, Debug)]
|
||||
pub enum VerifyError {
|
||||
#[error("An error occured while bcrypt verification: {0}")]
|
||||
BcryptError(#[from] bcrypt::BcryptError),
|
||||
#[error("Invalid argon2 password hash: {0}")]
|
||||
InvalidArgon2Hash(#[from] password_hash::Error),
|
||||
#[error("An error occured while argon2 verification: {0}")]
|
||||
Argon2Error(#[from] argon2::Error),
|
||||
}
|
||||
|
||||
#[crate::export]
|
||||
pub fn verify_password(password: &str, hash: &str) -> Result<bool, VerifyError> {
|
||||
if is_old_password_algorithm(hash) {
|
||||
Ok(bcrypt::verify(password, hash)?)
|
||||
} else {
|
||||
let parsed_hash = PasswordHash::new(hash)?;
|
||||
Ok(Argon2::default()
|
||||
.verify_password(password.as_bytes(), &parsed_hash)
|
||||
.is_ok())
|
||||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
#[crate::export]
|
||||
pub fn is_old_password_algorithm(hash: &str) -> bool {
|
||||
// bcrypt hashes start with $2[ab]$
|
||||
hash.starts_with("$2")
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod unit_test {
|
||||
use super::{hash_password, is_old_password_algorithm, verify_password};
|
||||
|
||||
#[test]
|
||||
fn verify_password_test() {
|
||||
let password = "omWc*%sD^fn7o2cXmc9e2QasBdrbRuhNB*gx!J5";
|
||||
|
||||
let hash = hash_password(password).unwrap();
|
||||
assert!(verify_password(password, hash.as_str()).unwrap());
|
||||
|
||||
let argon2_hash = "$argon2id$v=19$m=19456,t=2,p=1$jty3puDFd4ENv/lgHn3ROQ$kRHDdEoVv2rruvnF731E74NxnYlvj5FMgePdGIIq3Jk";
|
||||
let argon2_invalid_hash = "$argon2id$v=19$m=19456,t=2,p=1$jty3puDFd4ENv/lgHn3ROQ$kRHDdEoVv2rruvnF731E74NxnYlvj4FMgePdGIIq3Jk";
|
||||
let bcrypt_hash = "$2a$12$WzUc.20jgbHmQjUMqTr8vOhKqYbS1BUvubapv/GLjCK1IN.h4e4la";
|
||||
let bcrypt_invalid_hash = "$2a$12$WzUc.20jgbHmQjUMqTr7vOhKqYbS1BUvubapv/GLjCK1IN.h4e4la";
|
||||
|
||||
assert!(!is_old_password_algorithm(argon2_hash));
|
||||
assert!(is_old_password_algorithm(bcrypt_hash));
|
||||
|
||||
assert!(verify_password(password, argon2_hash).unwrap());
|
||||
assert!(verify_password(password, bcrypt_hash).unwrap());
|
||||
|
||||
assert!(!verify_password(password, argon2_invalid_hash).unwrap());
|
||||
assert!(!verify_password(password, bcrypt_invalid_hash).unwrap());
|
||||
}
|
||||
}
|
191
packages/backend-rs/src/misc/reaction.rs
Normal file
191
packages/backend-rs/src/misc/reaction.rs
Normal file
|
@ -0,0 +1,191 @@
|
|||
use crate::database::db_conn;
|
||||
use crate::misc::{convert_host::to_puny, emoji::is_unicode_emoji, meta::fetch_meta};
|
||||
use crate::model::entity::emoji;
|
||||
use once_cell::sync::Lazy;
|
||||
use regex::Regex;
|
||||
use sea_orm::prelude::*;
|
||||
use std::collections::HashMap;
|
||||
|
||||
#[derive(PartialEq, Debug)]
|
||||
#[crate::export(object)]
|
||||
pub struct DecodedReaction {
|
||||
pub reaction: String,
|
||||
pub name: Option<String>,
|
||||
pub host: Option<String>,
|
||||
}
|
||||
|
||||
#[crate::export]
|
||||
pub fn decode_reaction(reaction: &str) -> DecodedReaction {
|
||||
// Misskey allows you to include "+" and "-" in emoji shortcodes
|
||||
// MFM spec: https://github.com/misskey-dev/mfm.js/blob/6aaf68089023c6adebe44123eebbc4dcd75955e0/docs/syntax.md?plain=1#L583
|
||||
// Misskey's implementation: https://github.com/misskey-dev/misskey/blob/bba3097765317cbf95d09627961b5b5dce16a972/packages/backend/src/core/ReactionService.ts#L68
|
||||
static RE: Lazy<Regex> =
|
||||
Lazy::new(|| Regex::new(r"^:([0-9A-Za-z_+-]+)(?:@([0-9A-Za-z_.-]+))?:$").unwrap());
|
||||
|
||||
if let Some(captures) = RE.captures(reaction) {
|
||||
let name = &captures[1];
|
||||
let host = captures.get(2).map(|s| s.as_str());
|
||||
|
||||
DecodedReaction {
|
||||
reaction: format!(":{}@{}:", name, host.unwrap_or(".")),
|
||||
name: Some(name.to_owned()),
|
||||
host: host.map(|s| s.to_owned()),
|
||||
}
|
||||
} else {
|
||||
DecodedReaction {
|
||||
reaction: reaction.to_owned(),
|
||||
name: None,
|
||||
host: None,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[crate::export]
|
||||
pub fn count_reactions(reactions: &HashMap<String, u32>) -> HashMap<String, u32> {
|
||||
let mut res = HashMap::<String, u32>::new();
|
||||
|
||||
for (reaction, count) in reactions.iter() {
|
||||
if count > &0 {
|
||||
let decoded = decode_reaction(reaction).reaction;
|
||||
let total = res.entry(decoded).or_insert(0);
|
||||
*total += count;
|
||||
}
|
||||
}
|
||||
|
||||
res
|
||||
}
|
||||
|
||||
#[derive(thiserror::Error, Debug)]
|
||||
pub enum Error {
|
||||
#[error("Idna error: {0}")]
|
||||
IdnaError(#[from] idna::Errors),
|
||||
#[error("Database error: {0}")]
|
||||
DbError(#[from] DbErr),
|
||||
}
|
||||
|
||||
#[crate::export]
|
||||
pub async fn to_db_reaction(reaction: Option<&str>, host: Option<&str>) -> Result<String, Error> {
|
||||
if let Some(reaction) = reaction {
|
||||
// FIXME: Is it okay to do this only here?
|
||||
// This was introduced in https://firefish.dev/firefish/firefish/-/commit/af730e75b6fc1a57ca680ce83459d7e433b130cf
|
||||
if reaction.contains('❤') || reaction.contains("♥️") {
|
||||
return Ok("❤️".to_owned());
|
||||
}
|
||||
|
||||
if is_unicode_emoji(reaction) {
|
||||
return Ok(reaction.to_owned());
|
||||
}
|
||||
|
||||
static RE: Lazy<Regex> =
|
||||
Lazy::new(|| Regex::new(r"^:([0-9A-Za-z_+-]+)(?:@\.)?:$").unwrap());
|
||||
|
||||
if let Some(captures) = RE.captures(reaction) {
|
||||
let name = &captures[1];
|
||||
let db = db_conn().await?;
|
||||
|
||||
if let Some(host) = host {
|
||||
// remote emoji
|
||||
let ascii_host = to_puny(host)?;
|
||||
|
||||
// TODO: Does SeaORM have the `exists` method?
|
||||
if emoji::Entity::find()
|
||||
.filter(emoji::Column::Name.eq(name))
|
||||
.filter(emoji::Column::Host.eq(&ascii_host))
|
||||
.one(db)
|
||||
.await?
|
||||
.is_some()
|
||||
{
|
||||
return Ok(format!(":{name}@{ascii_host}:"));
|
||||
}
|
||||
} else {
|
||||
// local emoji
|
||||
// TODO: Does SeaORM have the `exists` method?
|
||||
if emoji::Entity::find()
|
||||
.filter(emoji::Column::Name.eq(name))
|
||||
.filter(emoji::Column::Host.is_null())
|
||||
.one(db)
|
||||
.await?
|
||||
.is_some()
|
||||
{
|
||||
return Ok(format!(":{name}:"));
|
||||
}
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
Ok(fetch_meta(true).await?.default_reaction)
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod unit_test {
|
||||
use super::{decode_reaction, DecodedReaction};
|
||||
use pretty_assertions::{assert_eq, assert_ne};
|
||||
|
||||
#[test]
|
||||
fn test_decode_reaction() {
|
||||
let unicode_emoji_1 = DecodedReaction {
|
||||
reaction: "⭐".to_string(),
|
||||
name: None,
|
||||
host: None,
|
||||
};
|
||||
let unicode_emoji_2 = DecodedReaction {
|
||||
reaction: "🩷".to_string(),
|
||||
name: None,
|
||||
host: None,
|
||||
};
|
||||
|
||||
assert_eq!(decode_reaction("⭐"), unicode_emoji_1);
|
||||
assert_eq!(decode_reaction("🩷"), unicode_emoji_2);
|
||||
|
||||
assert_ne!(decode_reaction("⭐"), unicode_emoji_2);
|
||||
assert_ne!(decode_reaction("🩷"), unicode_emoji_1);
|
||||
|
||||
let unicode_emoji_3 = DecodedReaction {
|
||||
reaction: "🖖🏿".to_string(),
|
||||
name: None,
|
||||
host: None,
|
||||
};
|
||||
assert_eq!(decode_reaction("🖖🏿"), unicode_emoji_3);
|
||||
|
||||
let local_emoji = DecodedReaction {
|
||||
reaction: ":meow_melt_tears@.:".to_string(),
|
||||
name: Some("meow_melt_tears".to_string()),
|
||||
host: None,
|
||||
};
|
||||
assert_eq!(decode_reaction(":meow_melt_tears:"), local_emoji);
|
||||
|
||||
let remote_emoji_1 = DecodedReaction {
|
||||
reaction: ":meow_uwu@some-domain.example.org:".to_string(),
|
||||
name: Some("meow_uwu".to_string()),
|
||||
host: Some("some-domain.example.org".to_string()),
|
||||
};
|
||||
assert_eq!(
|
||||
decode_reaction(":meow_uwu@some-domain.example.org:"),
|
||||
remote_emoji_1
|
||||
);
|
||||
|
||||
let remote_emoji_2 = DecodedReaction {
|
||||
reaction: ":C++23@xn--eckwd4c7c.example.org:".to_string(),
|
||||
name: Some("C++23".to_string()),
|
||||
host: Some("xn--eckwd4c7c.example.org".to_string()),
|
||||
};
|
||||
assert_eq!(
|
||||
decode_reaction(":C++23@xn--eckwd4c7c.example.org:"),
|
||||
remote_emoji_2
|
||||
);
|
||||
|
||||
let invalid_reaction_1 = DecodedReaction {
|
||||
reaction: ":foo".to_string(),
|
||||
name: None,
|
||||
host: None,
|
||||
};
|
||||
assert_eq!(decode_reaction(":foo"), invalid_reaction_1);
|
||||
|
||||
let invalid_reaction_2 = DecodedReaction {
|
||||
reaction: ":foo&@example.com:".to_string(),
|
||||
name: None,
|
||||
host: None,
|
||||
};
|
||||
assert_eq!(decode_reaction(":foo&@example.com:"), invalid_reaction_2);
|
||||
}
|
||||
}
|
|
@ -22,9 +22,9 @@
|
|||
"@swc/core-android-arm64": "1.3.11"
|
||||
},
|
||||
"dependencies": {
|
||||
"@bull-board/api": "5.15.3",
|
||||
"@bull-board/koa": "5.15.3",
|
||||
"@bull-board/ui": "5.15.3",
|
||||
"@bull-board/api": "5.15.5",
|
||||
"@bull-board/koa": "5.15.5",
|
||||
"@bull-board/ui": "5.15.5",
|
||||
"@discordapp/twemoji": "^15.0.3",
|
||||
"@koa/cors": "5.0.0",
|
||||
"@koa/multer": "3.0.2",
|
||||
|
@ -33,15 +33,12 @@
|
|||
"@peertube/http-signature": "1.7.0",
|
||||
"@redocly/openapi-core": "1.11.0",
|
||||
"@sinonjs/fake-timers": "11.2.2",
|
||||
"@twemoji/parser": "^15.1.1",
|
||||
"adm-zip": "0.5.10",
|
||||
"ajv": "8.12.0",
|
||||
"archiver": "7.0.1",
|
||||
"argon2": "^0.40.1",
|
||||
"aws-sdk": "2.1597.0",
|
||||
"aws-sdk": "2.1599.0",
|
||||
"axios": "^1.6.8",
|
||||
"backend-rs": "workspace:*",
|
||||
"bcryptjs": "2.4.3",
|
||||
"blurhash": "2.0.5",
|
||||
"bull": "4.12.2",
|
||||
"cacheable-lookup": "TheEssem/cacheable-lookup",
|
||||
|
@ -54,7 +51,7 @@
|
|||
"date-fns": "3.6.0",
|
||||
"decompress": "^4.2.1",
|
||||
"deep-email-validator": "0.1.21",
|
||||
"deepl-node": "1.12.0",
|
||||
"deepl-node": "1.13.0",
|
||||
"escape-regexp": "0.0.1",
|
||||
"feed": "4.2.2",
|
||||
"file-type": "19.0.0",
|
||||
|
@ -100,7 +97,7 @@
|
|||
"punycode": "2.3.1",
|
||||
"pureimage": "0.4.13",
|
||||
"qrcode": "1.5.3",
|
||||
"qs": "6.12.0",
|
||||
"qs": "6.12.1",
|
||||
"random-seed": "0.3.0",
|
||||
"ratelimiter": "3.4.1",
|
||||
"redis-semaphore": "5.5.1",
|
||||
|
@ -130,7 +127,6 @@
|
|||
"@swc/cli": "0.3.12",
|
||||
"@swc/core": "1.4.13",
|
||||
"@types/adm-zip": "^0.5.5",
|
||||
"@types/bcryptjs": "2.4.6",
|
||||
"@types/color-convert": "^2.0.3",
|
||||
"@types/content-disposition": "^0.5.8",
|
||||
"@types/escape-regexp": "0.0.3",
|
||||
|
|
|
@ -3,7 +3,7 @@ import chalk from "chalk";
|
|||
import Xev from "xev";
|
||||
|
||||
import Logger from "@/services/logger.js";
|
||||
import { envOption } from "../env.js";
|
||||
import { envOption } from "@/config/index.js";
|
||||
import { inspect } from "node:util";
|
||||
|
||||
// for typeorm
|
||||
|
@ -76,9 +76,7 @@ cluster.on("exit", (worker) => {
|
|||
});
|
||||
|
||||
// Display detail of unhandled promise rejection
|
||||
if (!envOption.quiet) {
|
||||
process.on("unhandledRejection", console.dir);
|
||||
}
|
||||
process.on("unhandledRejection", console.dir);
|
||||
|
||||
// Display detail of uncaught exception
|
||||
process.on("uncaughtException", (err) => {
|
||||
|
|
|
@ -10,7 +10,7 @@ import semver from "semver";
|
|||
import Logger from "@/services/logger.js";
|
||||
import loadConfig from "@/config/load.js";
|
||||
import type { Config } from "@/config/types.js";
|
||||
import { envOption } from "@/env.js";
|
||||
import { envOption } from "@/config/index.js";
|
||||
import { showMachineInfo } from "@/misc/show-machine-info.js";
|
||||
import { db, initDb } from "@/db/postgre.js";
|
||||
import { inspect } from "node:util";
|
||||
|
@ -28,58 +28,56 @@ const bootLogger = logger.createSubLogger("boot", "magenta", false);
|
|||
const themeColor = chalk.hex("#31748f");
|
||||
|
||||
function greet() {
|
||||
if (!envOption.quiet) {
|
||||
//#region Firefish logo
|
||||
console.log(
|
||||
themeColor(
|
||||
"██████╗ ██╗██████╗ ███████╗███████╗██╗███████╗██╗ ██╗ ○ ▄ ▄ ",
|
||||
),
|
||||
);
|
||||
console.log(
|
||||
themeColor(
|
||||
"██╔════╝██║██╔══██╗██╔════╝██╔════╝██║██╔════╝██║ ██║ ⚬ █▄▄ █▄▄ ",
|
||||
),
|
||||
);
|
||||
console.log(
|
||||
themeColor(
|
||||
"█████╗ ██║██████╔╝█████╗ █████╗ ██║███████╗███████║ ▄▄▄▄▄▄ ▄ ",
|
||||
),
|
||||
);
|
||||
console.log(
|
||||
themeColor(
|
||||
"██╔══╝ ██║██╔══██╗██╔══╝ ██╔══╝ ██║╚════██║██╔══██║ █ █ █▄▄ ",
|
||||
),
|
||||
);
|
||||
console.log(
|
||||
themeColor(
|
||||
"██║ ██║██║ ██║███████╗██║ ██║███████║██║ ██║ █ ● ● █ ",
|
||||
),
|
||||
);
|
||||
console.log(
|
||||
themeColor(
|
||||
"╚═╝ ╚═╝╚═╝ ╚═╝╚══════╝╚═╝ ╚═╝╚══════╝╚═╝ ╚═╝ ▀▄▄▄▄▄▄▀ ",
|
||||
),
|
||||
);
|
||||
//#endregion
|
||||
//#region Firefish logo
|
||||
console.log(
|
||||
themeColor(
|
||||
"██████╗ ██╗██████╗ ███████╗███████╗██╗███████╗██╗ ██╗ ○ ▄ ▄ ",
|
||||
),
|
||||
);
|
||||
console.log(
|
||||
themeColor(
|
||||
"██╔════╝██║██╔══██╗██╔════╝██╔════╝██║██╔════╝██║ ██║ ⚬ █▄▄ █▄▄ ",
|
||||
),
|
||||
);
|
||||
console.log(
|
||||
themeColor(
|
||||
"█████╗ ██║██████╔╝█████╗ █████╗ ██║███████╗███████║ ▄▄▄▄▄▄ ▄ ",
|
||||
),
|
||||
);
|
||||
console.log(
|
||||
themeColor(
|
||||
"██╔══╝ ██║██╔══██╗██╔══╝ ██╔══╝ ██║╚════██║██╔══██║ █ █ █▄▄ ",
|
||||
),
|
||||
);
|
||||
console.log(
|
||||
themeColor(
|
||||
"██║ ██║██║ ██║███████╗██║ ██║███████║██║ ██║ █ ● ● █ ",
|
||||
),
|
||||
);
|
||||
console.log(
|
||||
themeColor(
|
||||
"╚═╝ ╚═╝╚═╝ ╚═╝╚══════╝╚═╝ ╚═╝╚══════╝╚═╝ ╚═╝ ▀▄▄▄▄▄▄▀ ",
|
||||
),
|
||||
);
|
||||
//#endregion
|
||||
|
||||
console.log(
|
||||
" Firefish is an open-source decentralized microblogging platform.",
|
||||
);
|
||||
console.log(
|
||||
chalk.rgb(
|
||||
255,
|
||||
136,
|
||||
0,
|
||||
)(
|
||||
" If you like Firefish, please consider contributing to the repo. https://firefish.dev/firefish/firefish",
|
||||
),
|
||||
);
|
||||
console.log(
|
||||
" Firefish is an open-source decentralized microblogging platform.",
|
||||
);
|
||||
console.log(
|
||||
chalk.rgb(
|
||||
255,
|
||||
136,
|
||||
0,
|
||||
)(
|
||||
" If you like Firefish, please consider contributing to the repo. https://firefish.dev/firefish/firefish",
|
||||
),
|
||||
);
|
||||
|
||||
console.log("");
|
||||
console.log(
|
||||
chalkTemplate`--- ${os.hostname()} {gray (PID: ${process.pid.toString()})} ---`,
|
||||
);
|
||||
}
|
||||
console.log("");
|
||||
console.log(
|
||||
chalkTemplate`--- ${os.hostname()} {gray (PID: ${process.pid.toString()})} ---`,
|
||||
);
|
||||
|
||||
bootLogger.info("Welcome to Firefish!");
|
||||
bootLogger.info(`Firefish v${meta.version}`, null, true);
|
||||
|
|
|
@ -1,3 +1,5 @@
|
|||
import load from "./load.js";
|
||||
import { readEnvironmentConfig } from "backend-rs";
|
||||
|
||||
export default load();
|
||||
export const envOption = readEnvironmentConfig();
|
||||
|
|
|
@ -55,6 +55,7 @@ export default function load() {
|
|||
mixin.userAgent = `Firefish/${meta.version} (${config.url})`;
|
||||
mixin.clientEntry = clientManifest["src/init.ts"];
|
||||
|
||||
if (config.proxyRemoteFiles == null) config.proxyRemoteFiles = true;
|
||||
if (!config.redis.prefix) config.redis.prefix = mixin.hostname;
|
||||
if (config.cacheServer && !config.cacheServer.prefix)
|
||||
config.cacheServer.prefix = mixin.hostname;
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
import si from "systeminformation";
|
||||
import Xev from "xev";
|
||||
import * as osUtils from "os-utils";
|
||||
import { fetchMeta } from "@/misc/fetch-meta.js";
|
||||
import { fetchMeta } from "backend-rs";
|
||||
|
||||
const ev = new Xev();
|
||||
|
||||
|
@ -20,7 +20,7 @@ export default function () {
|
|||
ev.emit(`serverStatsLog:${x.id}`, log.slice(0, x.length || 50));
|
||||
});
|
||||
|
||||
fetchMeta().then((meta) => {
|
||||
fetchMeta(true).then((meta) => {
|
||||
if (!meta.enableServerMachineStats) return;
|
||||
});
|
||||
|
||||
|
|
|
@ -1,25 +0,0 @@
|
|||
const envOption = {
|
||||
onlyQueue: false,
|
||||
onlyServer: false,
|
||||
noDaemons: false,
|
||||
disableClustering: false,
|
||||
verbose: false,
|
||||
withLogTime: false,
|
||||
quiet: false,
|
||||
slow: false,
|
||||
};
|
||||
|
||||
for (const key of Object.keys(envOption) as (keyof typeof envOption)[]) {
|
||||
if (
|
||||
process.env[
|
||||
`MK_${key.replace(/[A-Z]/g, (letter) => `_${letter}`).toUpperCase()}`
|
||||
]
|
||||
)
|
||||
envOption[key] = true;
|
||||
}
|
||||
|
||||
if (process.env.NODE_ENV === "test") envOption.disableClustering = true;
|
||||
if (process.env.NODE_ENV === "test") envOption.quiet = true;
|
||||
if (process.env.NODE_ENV === "test") envOption.noDaemons = true;
|
||||
|
||||
export { envOption };
|
|
@ -1,17 +0,0 @@
|
|||
export function convertMilliseconds(ms: number) {
|
||||
let seconds = Math.round(ms / 1000);
|
||||
let minutes = Math.round(seconds / 60);
|
||||
let hours = Math.round(minutes / 60);
|
||||
const days = Math.round(hours / 24);
|
||||
seconds %= 60;
|
||||
minutes %= 60;
|
||||
hours %= 24;
|
||||
|
||||
const result = [];
|
||||
if (days > 0) result.push(`${days} day(s)`);
|
||||
if (hours > 0) result.push(`${hours} hour(s)`);
|
||||
if (minutes > 0) result.push(`${minutes} minute(s)`);
|
||||
if (seconds > 0) result.push(`${seconds} second(s)`);
|
||||
|
||||
return result.join(", ");
|
||||
}
|
|
@ -1,5 +0,0 @@
|
|||
import twemoji from "@twemoji/parser/dist/lib/regex.js";
|
||||
const twemojiRegex = twemoji.default;
|
||||
|
||||
export const emojiRegex = new RegExp(`(${twemojiRegex.source})`);
|
||||
export const emojiRegexAtStartToEnd = new RegExp(`^(${twemojiRegex.source})$`);
|
|
@ -1,72 +0,0 @@
|
|||
import { db } from "@/db/postgre.js";
|
||||
import { Meta } from "@/models/entities/meta.js";
|
||||
|
||||
let cache: Meta;
|
||||
|
||||
export function metaToPugArgs(meta: Meta): object {
|
||||
let motd = ["Loading..."];
|
||||
if (meta.customMotd.length > 0) {
|
||||
motd = meta.customMotd;
|
||||
}
|
||||
let splashIconUrl = meta.iconUrl;
|
||||
if (meta.customSplashIcons.length > 0) {
|
||||
splashIconUrl =
|
||||
meta.customSplashIcons[
|
||||
Math.floor(Math.random() * meta.customSplashIcons.length)
|
||||
];
|
||||
}
|
||||
|
||||
return {
|
||||
img: meta.bannerUrl,
|
||||
title: meta.name || "Firefish",
|
||||
instanceName: meta.name || "Firefish",
|
||||
desc: meta.description,
|
||||
icon: meta.iconUrl,
|
||||
splashIcon: splashIconUrl,
|
||||
themeColor: meta.themeColor,
|
||||
randomMOTD: motd[Math.floor(Math.random() * motd.length)],
|
||||
privateMode: meta.privateMode,
|
||||
};
|
||||
}
|
||||
|
||||
export async function fetchMeta(noCache = false): Promise<Meta> {
|
||||
if (!noCache && cache) return cache;
|
||||
|
||||
return await db.transaction(async (transactionalEntityManager) => {
|
||||
// New IDs are prioritized because multiple records may have been created due to past bugs.
|
||||
const metas = await transactionalEntityManager.find(Meta, {
|
||||
order: {
|
||||
id: "DESC",
|
||||
},
|
||||
});
|
||||
|
||||
const meta = metas[0];
|
||||
|
||||
if (meta) {
|
||||
cache = meta;
|
||||
return meta;
|
||||
} else {
|
||||
// If fetchMeta is called at the same time when meta is empty, this part may be called at the same time, so use fail-safe upsert.
|
||||
const saved = await transactionalEntityManager
|
||||
.upsert(
|
||||
Meta,
|
||||
{
|
||||
id: "x",
|
||||
},
|
||||
["id"],
|
||||
)
|
||||
.then((x) =>
|
||||
transactionalEntityManager.findOneByOrFail(Meta, x.identifiers[0]),
|
||||
);
|
||||
|
||||
cache = saved;
|
||||
return saved;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
setInterval(() => {
|
||||
fetchMeta(true).then((meta) => {
|
||||
cache = meta;
|
||||
});
|
||||
}, 1000 * 10);
|
|
@ -1,9 +1,9 @@
|
|||
import { fetchMeta } from "./fetch-meta.js";
|
||||
import { fetchMeta } from "backend-rs";
|
||||
import type { ILocalUser } from "@/models/entities/user.js";
|
||||
import { Users } from "@/models/index.js";
|
||||
|
||||
export async function fetchProxyAccount(): Promise<ILocalUser | null> {
|
||||
const meta = await fetchMeta();
|
||||
const meta = await fetchMeta(true);
|
||||
if (meta.proxyAccountId == null) return null;
|
||||
return (await Users.findOneByOrFail({
|
||||
id: meta.proxyAccountId,
|
||||
|
|
|
@ -1,20 +0,0 @@
|
|||
import bcrypt from "bcryptjs";
|
||||
import * as argon2 from "argon2";
|
||||
|
||||
export async function hashPassword(password: string): Promise<string> {
|
||||
return argon2.hash(password);
|
||||
}
|
||||
|
||||
export async function comparePassword(
|
||||
password: string,
|
||||
hash: string,
|
||||
): Promise<boolean> {
|
||||
if (isOldAlgorithm(hash)) return bcrypt.compare(password, hash);
|
||||
|
||||
return argon2.verify(hash, password);
|
||||
}
|
||||
|
||||
export function isOldAlgorithm(hash: string): boolean {
|
||||
// bcrypt hashes start with $2[ab]$
|
||||
return hash.startsWith("$2");
|
||||
}
|
|
@ -3,8 +3,7 @@ import { Emojis } from "@/models/index.js";
|
|||
import type { Emoji } from "@/models/entities/emoji.js";
|
||||
import type { Note } from "@/models/entities/note.js";
|
||||
import { Cache } from "./cache.js";
|
||||
import { isSelfHost, toPuny } from "backend-rs";
|
||||
import { decodeReaction } from "./reaction-lib.js";
|
||||
import { decodeReaction, isSelfHost, toPuny } from "backend-rs";
|
||||
import config from "@/config/index.js";
|
||||
import { query } from "@/prelude/url.js";
|
||||
import { redisClient } from "@/db/redis.js";
|
||||
|
|
|
@ -12,7 +12,7 @@ export function parse(acct: any): Post {
|
|||
cw: acct.cw,
|
||||
localOnly: acct.localOnly,
|
||||
createdAt: new Date(acct.createdAt),
|
||||
visibility: "hidden" + (acct.visibility || ""),
|
||||
visibility: `hidden${acct.visibility || ""}`,
|
||||
};
|
||||
}
|
||||
|
||||
|
|
|
@ -1,87 +0,0 @@
|
|||
import { emojiRegex } from "./emoji-regex.js";
|
||||
import { fetchMeta } from "./fetch-meta.js";
|
||||
import { Emojis } from "@/models/index.js";
|
||||
import { toPuny } from "backend-rs";
|
||||
import { IsNull } from "typeorm";
|
||||
|
||||
export function convertReactions(reactions: Record<string, number>) {
|
||||
const result = new Map();
|
||||
|
||||
for (const reaction in reactions) {
|
||||
if (reactions[reaction] <= 0) continue;
|
||||
|
||||
const decoded = decodeReaction(reaction).reaction;
|
||||
result.set(decoded, (result.get(decoded) || 0) + reactions[reaction]);
|
||||
}
|
||||
|
||||
return Object.fromEntries(result);
|
||||
}
|
||||
|
||||
export async function toDbReaction(
|
||||
reaction?: string | null,
|
||||
reacterHost?: string | null,
|
||||
): Promise<string> {
|
||||
if (!reaction) return (await fetchMeta()).defaultReaction;
|
||||
|
||||
reacterHost = reacterHost == null ? null : toPuny(reacterHost);
|
||||
|
||||
if (reaction.includes("❤") || reaction.includes("♥️")) return "❤️";
|
||||
|
||||
// Allow unicode reactions
|
||||
const match = emojiRegex.exec(reaction);
|
||||
if (match) {
|
||||
const unicode = match[0];
|
||||
return unicode;
|
||||
}
|
||||
|
||||
const custom = reaction.match(/^:([\w+-]+)(?:@\.)?:$/);
|
||||
if (custom) {
|
||||
const name = custom[1];
|
||||
const emoji = await Emojis.findOneBy({
|
||||
host: reacterHost || IsNull(),
|
||||
name,
|
||||
});
|
||||
|
||||
if (emoji) return reacterHost ? `:${name}@${reacterHost}:` : `:${name}:`;
|
||||
}
|
||||
|
||||
return (await fetchMeta()).defaultReaction;
|
||||
}
|
||||
|
||||
type DecodedReaction = {
|
||||
/**
|
||||
* リアクション名 (Unicode Emoji or ':name@hostname' or ':name@.')
|
||||
*/
|
||||
reaction: string;
|
||||
|
||||
/**
|
||||
* name (カスタム絵文字の場合name, Emojiクエリに使う)
|
||||
*/
|
||||
name?: string;
|
||||
|
||||
/**
|
||||
* host (カスタム絵文字の場合host, Emojiクエリに使う)
|
||||
*/
|
||||
host?: string | null;
|
||||
};
|
||||
|
||||
export function decodeReaction(str: string): DecodedReaction {
|
||||
const custom = str.match(/^:([\w+-]+)(?:@([\w.-]+))?:$/);
|
||||
|
||||
if (custom) {
|
||||
const name = custom[1];
|
||||
const host = custom[2] || null;
|
||||
|
||||
return {
|
||||
reaction: `:${name}@${host || "."}:`, // ローカル分は@以降を省略するのではなく.にする
|
||||
name,
|
||||
host,
|
||||
};
|
||||
}
|
||||
|
||||
return {
|
||||
reaction: str,
|
||||
name: undefined,
|
||||
host: undefined,
|
||||
};
|
||||
}
|
|
@ -1,3 +0,0 @@
|
|||
export function safeForSql(text: string): boolean {
|
||||
return !/[\0\x08\x09\x1a\n\r"'\\\%]/g.test(text);
|
||||
}
|
|
@ -1,4 +1,4 @@
|
|||
import { fetchMeta } from "@/misc/fetch-meta.js";
|
||||
import { fetchMeta } from "backend-rs";
|
||||
import type { Instance } from "@/models/entities/instance.js";
|
||||
import type { Meta } from "@/models/entities/meta.js";
|
||||
|
||||
|
@ -13,7 +13,7 @@ export async function shouldBlockInstance(
|
|||
host: Instance["host"],
|
||||
meta?: Meta,
|
||||
): Promise<boolean> {
|
||||
const { blockedHosts } = meta ?? (await fetchMeta());
|
||||
const { blockedHosts } = meta ?? (await fetchMeta(true));
|
||||
return blockedHosts.some(
|
||||
(blockedHost) => host === blockedHost || host.endsWith(`.${blockedHost}`),
|
||||
);
|
||||
|
@ -30,7 +30,7 @@ export async function shouldSilenceInstance(
|
|||
host: Instance["host"],
|
||||
meta?: Meta,
|
||||
): Promise<boolean> {
|
||||
const { silencedHosts } = meta ?? (await fetchMeta());
|
||||
const { silencedHosts } = meta ?? (await fetchMeta(true));
|
||||
return silencedHosts.some(
|
||||
(silencedHost) =>
|
||||
host === silencedHost || host.endsWith(`.${silencedHost}`),
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
import { Brackets } from "typeorm";
|
||||
import { fetchMeta } from "@/misc/fetch-meta.js";
|
||||
import { fetchMeta } from "backend-rs";
|
||||
import { Instances } from "@/models/index.js";
|
||||
import type { Instance } from "@/models/entities/instance.js";
|
||||
import { DAY } from "@/const.js";
|
||||
|
@ -19,7 +19,7 @@ export async function skippedInstances(
|
|||
hosts: Instance["host"][],
|
||||
): Promise<Instance["host"][]> {
|
||||
// first check for blocked instances since that info may already be in memory
|
||||
const meta = await fetchMeta();
|
||||
const meta = await fetchMeta(true);
|
||||
const shouldSkip = await Promise.all(
|
||||
hosts.map((host) => shouldBlockInstance(host, meta)),
|
||||
);
|
||||
|
|
|
@ -1,3 +0,0 @@
|
|||
export function sqlLikeEscape(s: string) {
|
||||
return s.replace(/([%_])/g, "\\$1");
|
||||
}
|
|
@ -1,7 +1,7 @@
|
|||
import fetch from "node-fetch";
|
||||
import { Converter } from "opencc-js";
|
||||
import { getAgentByUrl } from "@/misc/fetch.js";
|
||||
import { fetchMeta } from "@/misc/fetch-meta.js";
|
||||
import { fetchMeta } from "backend-rs";
|
||||
import type { PostLanguage } from "@/misc/langmap";
|
||||
import * as deepl from "deepl-node";
|
||||
|
||||
|
@ -26,7 +26,7 @@ export async function translate(
|
|||
from: PostLanguage | null,
|
||||
to: PostLanguage,
|
||||
) {
|
||||
const instance = await fetchMeta();
|
||||
const instance = await fetchMeta(true);
|
||||
|
||||
if (instance.deeplAuthKey == null && instance.libreTranslateApiUrl == null) {
|
||||
throw Error("No translator is set up on this server.");
|
||||
|
|
|
@ -2,7 +2,7 @@ import { db } from "@/db/postgre.js";
|
|||
import { NoteReaction } from "@/models/entities/note-reaction.js";
|
||||
import { Notes, Users } from "../index.js";
|
||||
import type { Packed } from "@/misc/schema.js";
|
||||
import { decodeReaction } from "@/misc/reaction-lib.js";
|
||||
import { decodeReaction } from "backend-rs";
|
||||
import type { User } from "@/models/entities/user.js";
|
||||
|
||||
export const NoteReactionRepository = db.getRepository(NoteReaction).extend({
|
||||
|
|
|
@ -12,9 +12,8 @@ import {
|
|||
Channels,
|
||||
} from "../index.js";
|
||||
import type { Packed } from "@/misc/schema.js";
|
||||
import { nyaify } from "backend-rs";
|
||||
import { countReactions, decodeReaction, nyaify } from "backend-rs";
|
||||
import { awaitAll } from "@/prelude/await-all.js";
|
||||
import { convertReactions, decodeReaction } from "@/misc/reaction-lib.js";
|
||||
import type { NoteReaction } from "@/models/entities/note-reaction.js";
|
||||
import {
|
||||
aggregateNoteEmojis,
|
||||
|
@ -214,7 +213,7 @@ export const NoteRepository = db.getRepository(Note).extend({
|
|||
note.visibility === "specified" ? note.visibleUserIds : undefined,
|
||||
renoteCount: note.renoteCount,
|
||||
repliesCount: note.repliesCount,
|
||||
reactions: convertReactions(note.reactions),
|
||||
reactions: countReactions(note.reactions),
|
||||
reactionEmojis: reactionEmoji,
|
||||
emojis: noteEmoji,
|
||||
tags: note.tags.length > 0 ? note.tags : undefined,
|
||||
|
|
|
@ -5,7 +5,7 @@ import config from "@/config/index.js";
|
|||
import type { DriveFile } from "@/models/entities/drive-file.js";
|
||||
import type { IActivity } from "@/remote/activitypub/type.js";
|
||||
import type { Webhook, webhookEventTypes } from "@/models/entities/webhook.js";
|
||||
import { envOption } from "../env.js";
|
||||
import { envOption } from "@/config/index.js";
|
||||
|
||||
import processDeliver from "./processors/deliver.js";
|
||||
import processInbox from "./processors/inbox.js";
|
||||
|
|
|
@ -5,7 +5,7 @@ import perform from "@/remote/activitypub/perform.js";
|
|||
import Logger from "@/services/logger.js";
|
||||
import { registerOrFetchInstanceDoc } from "@/services/register-or-fetch-instance-doc.js";
|
||||
import { Instances } from "@/models/index.js";
|
||||
import { fetchMeta } from "@/misc/fetch-meta.js";
|
||||
import { fetchMeta } from "backend-rs";
|
||||
import { toPuny, extractHost } from "backend-rs";
|
||||
import { getApId } from "@/remote/activitypub/type.js";
|
||||
import { fetchInstanceMetadata } from "@/services/fetch-instance-metadata.js";
|
||||
|
@ -41,7 +41,7 @@ export default async (job: Bull.Job<InboxJobData>): Promise<string> => {
|
|||
const host = toPuny(new URL(signature.keyId).hostname);
|
||||
|
||||
// interrupt if blocked
|
||||
const meta = await fetchMeta();
|
||||
const meta = await fetchMeta(true);
|
||||
if (await shouldBlockInstance(host, meta)) {
|
||||
return `Blocked request: ${host}`;
|
||||
}
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
import { URL } from "url";
|
||||
import httpSignature, { IParsedSignature } from "@peertube/http-signature";
|
||||
import config from "@/config/index.js";
|
||||
import { fetchMeta } from "@/misc/fetch-meta.js";
|
||||
import { fetchMeta } from "backend-rs";
|
||||
import { toPuny } from "backend-rs";
|
||||
import DbResolver from "@/remote/activitypub/db-resolver.js";
|
||||
import { getApId } from "@/remote/activitypub/type.js";
|
||||
|
@ -12,7 +12,7 @@ import type { UserPublickey } from "@/models/entities/user-publickey.js";
|
|||
import { verify } from "node:crypto";
|
||||
|
||||
export async function hasSignature(req: IncomingMessage): Promise<string> {
|
||||
const meta = await fetchMeta();
|
||||
const meta = await fetchMeta(true);
|
||||
const required = meta.secureMode || meta.privateMode;
|
||||
|
||||
try {
|
||||
|
@ -27,7 +27,7 @@ export async function hasSignature(req: IncomingMessage): Promise<string> {
|
|||
}
|
||||
|
||||
export async function checkFetch(req: IncomingMessage): Promise<number> {
|
||||
const meta = await fetchMeta();
|
||||
const meta = await fetchMeta(true);
|
||||
if (meta.secureMode || meta.privateMode) {
|
||||
if (req.headers.host !== config.host) return 400;
|
||||
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
import type { CacheableRemoteUser } from "@/models/entities/user.js";
|
||||
import deleteNode from "@/services/note/delete.js";
|
||||
import deleteNote from "@/services/note/delete.js";
|
||||
import { apLogger } from "../../logger.js";
|
||||
import DbResolver from "../../db-resolver.js";
|
||||
import { getApLock } from "@/misc/app-lock.js";
|
||||
|
@ -36,7 +36,7 @@ export default async function (
|
|||
return "The user trying to delete the post is not the post author";
|
||||
}
|
||||
|
||||
await deleteNode(actor, note);
|
||||
await deleteNote(actor, note);
|
||||
return "ok: note deleted";
|
||||
} finally {
|
||||
await lock.release();
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
import { uploadFromUrl } from "@/services/drive/upload-from-url.js";
|
||||
import type { CacheableRemoteUser } from "@/models/entities/user.js";
|
||||
import Resolver from "../resolver.js";
|
||||
import { fetchMeta } from "@/misc/fetch-meta.js";
|
||||
import { fetchMeta } from "backend-rs";
|
||||
import { apLogger } from "../logger.js";
|
||||
import type { DriveFile } from "@/models/entities/drive-file.js";
|
||||
import { DriveFiles } from "@/models/index.js";
|
||||
|
@ -34,7 +34,7 @@ export async function createImage(
|
|||
|
||||
logger.info(`Creating the Image: ${image.url}`);
|
||||
|
||||
const instance = await fetchMeta();
|
||||
const instance = await fetchMeta(true);
|
||||
|
||||
let file = await uploadFromUrl({
|
||||
url: image.url,
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
import config from "@/config/index.js";
|
||||
import type { ILocalUser } from "@/models/entities/user.js";
|
||||
import { getInstanceActor } from "@/services/instance-actor.js";
|
||||
import { fetchMeta } from "@/misc/fetch-meta.js";
|
||||
import { fetchMeta } from "backend-rs";
|
||||
import { extractHost, isSelfHost } from "backend-rs";
|
||||
import { apGet } from "./request.js";
|
||||
import type { IObject, ICollection, IOrderedCollection } from "./type.js";
|
||||
|
@ -100,7 +100,7 @@ export default class Resolver {
|
|||
return await this.resolveLocal(value);
|
||||
}
|
||||
|
||||
const meta = await fetchMeta();
|
||||
const meta = await fetchMeta(true);
|
||||
if (await shouldBlockInstance(host, meta)) {
|
||||
throw new Error("Instance is blocked");
|
||||
}
|
||||
|
|
|
@ -9,7 +9,7 @@ import renderKey from "@/remote/activitypub/renderer/key.js";
|
|||
import { renderPerson } from "@/remote/activitypub/renderer/person.js";
|
||||
import renderEmoji from "@/remote/activitypub/renderer/emoji.js";
|
||||
import { inbox as processInbox } from "@/queue/index.js";
|
||||
import { isSelfHost } from "backend-rs";
|
||||
import { fetchMeta, isSelfHost } from "backend-rs";
|
||||
import {
|
||||
Notes,
|
||||
Users,
|
||||
|
@ -25,7 +25,6 @@ import {
|
|||
getSignatureUser,
|
||||
} from "@/remote/activitypub/check-fetch.js";
|
||||
import { getInstanceActor } from "@/services/instance-actor.js";
|
||||
import { fetchMeta } from "@/misc/fetch-meta.js";
|
||||
import renderFollow from "@/remote/activitypub/renderer/follow.js";
|
||||
import Featured from "./activitypub/featured.js";
|
||||
import Following from "./activitypub/following.js";
|
||||
|
@ -238,7 +237,7 @@ router.get("/notes/:note", async (ctx, next) => {
|
|||
|
||||
ctx.body = renderActivity(await renderNote(note, false));
|
||||
|
||||
const meta = await fetchMeta();
|
||||
const meta = await fetchMeta(true);
|
||||
if (meta.secureMode || meta.privateMode) {
|
||||
ctx.set("Cache-Control", "private, max-age=0, must-revalidate");
|
||||
} else {
|
||||
|
@ -268,7 +267,7 @@ router.get("/notes/:note/activity", async (ctx) => {
|
|||
}
|
||||
|
||||
ctx.body = renderActivity(await packActivity(note));
|
||||
const meta = await fetchMeta();
|
||||
const meta = await fetchMeta(true);
|
||||
if (meta.secureMode || meta.privateMode) {
|
||||
ctx.set("Cache-Control", "private, max-age=0, must-revalidate");
|
||||
} else {
|
||||
|
@ -323,7 +322,7 @@ router.get("/users/:user/publickey", async (ctx) => {
|
|||
|
||||
if (Users.isLocalUser(user)) {
|
||||
ctx.body = renderActivity(renderKey(user, keypair));
|
||||
const meta = await fetchMeta();
|
||||
const meta = await fetchMeta(true);
|
||||
if (meta.secureMode || meta.privateMode) {
|
||||
ctx.set("Cache-Control", "private, max-age=0, must-revalidate");
|
||||
} else {
|
||||
|
@ -343,7 +342,7 @@ async function userInfo(ctx: Router.RouterContext, user: User | null) {
|
|||
}
|
||||
|
||||
ctx.body = renderActivity(await renderPerson(user as ILocalUser));
|
||||
const meta = await fetchMeta();
|
||||
const meta = await fetchMeta(true);
|
||||
if (meta.secureMode || meta.privateMode) {
|
||||
ctx.set("Cache-Control", "private, max-age=0, must-revalidate");
|
||||
} else {
|
||||
|
@ -426,8 +425,8 @@ router.get("/emojis/:emoji", async (ctx) => {
|
|||
return;
|
||||
}
|
||||
|
||||
ctx.body = renderActivity(await renderEmoji(emoji));
|
||||
const meta = await fetchMeta();
|
||||
ctx.body = renderActivity(renderEmoji(emoji));
|
||||
const meta = await fetchMeta(true);
|
||||
if (meta.secureMode || meta.privateMode) {
|
||||
ctx.set("Cache-Control", "private, max-age=0, must-revalidate");
|
||||
} else {
|
||||
|
@ -459,7 +458,7 @@ router.get("/likes/:like", async (ctx) => {
|
|||
}
|
||||
|
||||
ctx.body = renderActivity(await renderLike(reaction, note));
|
||||
const meta = await fetchMeta();
|
||||
const meta = await fetchMeta(true);
|
||||
if (meta.secureMode || meta.privateMode) {
|
||||
ctx.set("Cache-Control", "private, max-age=0, must-revalidate");
|
||||
} else {
|
||||
|
@ -497,7 +496,7 @@ router.get(
|
|||
}
|
||||
|
||||
ctx.body = renderActivity(renderFollow(follower, followee));
|
||||
const meta = await fetchMeta();
|
||||
const meta = await fetchMeta(true);
|
||||
if (meta.secureMode || meta.privateMode) {
|
||||
ctx.set("Cache-Control", "private, max-age=0, must-revalidate");
|
||||
} else {
|
||||
|
@ -540,7 +539,7 @@ router.get("/follows/:followRequestId", async (ctx: Router.RouterContext) => {
|
|||
return;
|
||||
}
|
||||
|
||||
const meta = await fetchMeta();
|
||||
const meta = await fetchMeta(true);
|
||||
if (meta.secureMode || meta.privateMode) {
|
||||
ctx.set("Cache-Control", "private, max-age=0, must-revalidate");
|
||||
} else {
|
||||
|
|
|
@ -5,7 +5,7 @@ import renderOrderedCollection from "@/remote/activitypub/renderer/ordered-colle
|
|||
import renderNote from "@/remote/activitypub/renderer/note.js";
|
||||
import { Users, Notes, UserNotePinings } from "@/models/index.js";
|
||||
import { checkFetch } from "@/remote/activitypub/check-fetch.js";
|
||||
import { fetchMeta } from "@/misc/fetch-meta.js";
|
||||
import { fetchMeta } from "backend-rs";
|
||||
import { setResponseType } from "../activitypub.js";
|
||||
import type Router from "@koa/router";
|
||||
|
||||
|
@ -57,7 +57,7 @@ export default async (ctx: Router.RouterContext) => {
|
|||
|
||||
ctx.body = renderActivity(rendered);
|
||||
|
||||
const meta = await fetchMeta();
|
||||
const meta = await fetchMeta(true);
|
||||
if (meta.secureMode || meta.privateMode) {
|
||||
ctx.set("Cache-Control", "private, max-age=0, must-revalidate");
|
||||
} else {
|
||||
|
|
|
@ -8,7 +8,7 @@ import renderFollowUser from "@/remote/activitypub/renderer/follow-user.js";
|
|||
import { Users, Followings, UserProfiles } from "@/models/index.js";
|
||||
import type { Following } from "@/models/entities/following.js";
|
||||
import { checkFetch } from "@/remote/activitypub/check-fetch.js";
|
||||
import { fetchMeta } from "@/misc/fetch-meta.js";
|
||||
import { fetchMeta } from "backend-rs";
|
||||
import { setResponseType } from "../activitypub.js";
|
||||
import type { FindOptionsWhere } from "typeorm";
|
||||
import type Router from "@koa/router";
|
||||
|
@ -110,7 +110,7 @@ export default async (ctx: Router.RouterContext) => {
|
|||
ctx.body = renderActivity(rendered);
|
||||
setResponseType(ctx);
|
||||
}
|
||||
const meta = await fetchMeta();
|
||||
const meta = await fetchMeta(true);
|
||||
if (meta.secureMode || meta.privateMode) {
|
||||
ctx.set("Cache-Control", "private, max-age=0, must-revalidate");
|
||||
} else {
|
||||
|
|
|
@ -8,7 +8,7 @@ import renderFollowUser from "@/remote/activitypub/renderer/follow-user.js";
|
|||
import { Users, Followings, UserProfiles } from "@/models/index.js";
|
||||
import type { Following } from "@/models/entities/following.js";
|
||||
import { checkFetch } from "@/remote/activitypub/check-fetch.js";
|
||||
import { fetchMeta } from "@/misc/fetch-meta.js";
|
||||
import { fetchMeta } from "backend-rs";
|
||||
import { setResponseType } from "../activitypub.js";
|
||||
import type { FindOptionsWhere } from "typeorm";
|
||||
import type Router from "@koa/router";
|
||||
|
@ -110,7 +110,7 @@ export default async (ctx: Router.RouterContext) => {
|
|||
ctx.body = renderActivity(rendered);
|
||||
setResponseType(ctx);
|
||||
}
|
||||
const meta = await fetchMeta();
|
||||
const meta = await fetchMeta(true);
|
||||
if (meta.secureMode || meta.privateMode) {
|
||||
ctx.set("Cache-Control", "private, max-age=0, must-revalidate");
|
||||
} else {
|
||||
|
|
|
@ -11,7 +11,7 @@ import * as url from "@/prelude/url.js";
|
|||
import { Users, Notes } from "@/models/index.js";
|
||||
import type { Note } from "@/models/entities/note.js";
|
||||
import { checkFetch } from "@/remote/activitypub/check-fetch.js";
|
||||
import { fetchMeta } from "@/misc/fetch-meta.js";
|
||||
import { fetchMeta } from "backend-rs";
|
||||
import { makePaginationQuery } from "../api/common/make-pagination-query.js";
|
||||
import { setResponseType } from "../activitypub.js";
|
||||
import type Router from "@koa/router";
|
||||
|
@ -117,7 +117,7 @@ export default async (ctx: Router.RouterContext) => {
|
|||
|
||||
setResponseType(ctx);
|
||||
}
|
||||
const meta = await fetchMeta();
|
||||
const meta = await fetchMeta(true);
|
||||
if (meta.secureMode || meta.privateMode) {
|
||||
ctx.set("Cache-Control", "private, max-age=0, must-revalidate");
|
||||
} else {
|
||||
|
|
|
@ -2,7 +2,7 @@ import type Koa from "koa";
|
|||
|
||||
import type { User } from "@/models/entities/user.js";
|
||||
import { UserIps } from "@/models/index.js";
|
||||
import { fetchMeta } from "@/misc/fetch-meta.js";
|
||||
import { fetchMeta } from "backend-rs";
|
||||
import type { IEndpoint } from "./endpoints.js";
|
||||
import authenticate, { AuthenticationError } from "./authenticate.js";
|
||||
import call from "./call.js";
|
||||
|
@ -84,7 +84,7 @@ export default (endpoint: IEndpoint, ctx: Koa.Context) =>
|
|||
|
||||
// Log IP
|
||||
if (user) {
|
||||
fetchMeta().then((meta) => {
|
||||
fetchMeta(true).then((meta) => {
|
||||
if (!meta.enableIpLogging) return;
|
||||
const ip = ctx.ip;
|
||||
const ips = userIpHistories.get(user.id);
|
||||
|
|
|
@ -10,7 +10,7 @@ import endpoints from "./endpoints.js";
|
|||
import compatibility from "./compatibility.js";
|
||||
import { ApiError } from "./error.js";
|
||||
import { apiLogger } from "./logger.js";
|
||||
import { fetchMeta } from "@/misc/fetch-meta.js";
|
||||
import { fetchMeta } from "backend-rs";
|
||||
|
||||
const accessDenied = {
|
||||
message: "Access denied.",
|
||||
|
@ -117,7 +117,7 @@ export default async (
|
|||
}
|
||||
|
||||
// private mode
|
||||
const meta = await fetchMeta();
|
||||
const meta = await fetchMeta(true);
|
||||
if (
|
||||
meta.privateMode &&
|
||||
ep.meta.requireCredentialPrivateMode &&
|
||||
|
|
|
@ -4,12 +4,11 @@ import { User } from "@/models/entities/user.js";
|
|||
import { Users, UsedUsernames } from "@/models/index.js";
|
||||
import { UserProfile } from "@/models/entities/user-profile.js";
|
||||
import { IsNull } from "typeorm";
|
||||
import { genId, toPuny } from "backend-rs";
|
||||
import { genId, hashPassword, toPuny } from "backend-rs";
|
||||
import { UserKeypair } from "@/models/entities/user-keypair.js";
|
||||
import { UsedUsername } from "@/models/entities/used-username.js";
|
||||
import { db } from "@/db/postgre.js";
|
||||
import config from "@/config/index.js";
|
||||
import { hashPassword } from "@/misc/password.js";
|
||||
|
||||
export async function signup(opts: {
|
||||
username: User["username"];
|
||||
|
@ -40,7 +39,7 @@ export async function signup(opts: {
|
|||
}
|
||||
|
||||
// Generate hash of password
|
||||
hash = await hashPassword(password);
|
||||
hash = hashPassword(password);
|
||||
}
|
||||
|
||||
// Generate secret
|
||||
|
|
|
@ -1,8 +1,7 @@
|
|||
import define from "@/server/api/define.js";
|
||||
import { Emojis } from "@/models/index.js";
|
||||
import { toPuny } from "backend-rs";
|
||||
import { sqlLikeEscape, toPuny } from "backend-rs";
|
||||
import { makePaginationQuery } from "@/server/api/common/make-pagination-query.js";
|
||||
import { sqlLikeEscape } from "@/misc/sql-like-escape.js";
|
||||
import { ApiError } from "@/server/api/error.js";
|
||||
|
||||
export const meta = {
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
import define from "@/server/api/define.js";
|
||||
import { Emojis } from "@/models/index.js";
|
||||
import { makePaginationQuery } from "../../../common/make-pagination-query.js";
|
||||
import { makePaginationQuery } from "@/server/api/common/make-pagination-query.js";
|
||||
import type { Emoji } from "@/models/entities/emoji.js";
|
||||
//import { sqlLikeEscape } from "@/misc/sql-like-escape.js";
|
||||
//import { sqlLikeEscape } from "backend-rs";
|
||||
import { ApiError } from "@/server/api/error.js";
|
||||
|
||||
export const meta = {
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
import config from "@/config/index.js";
|
||||
import { fetchMeta } from "@/misc/fetch-meta.js";
|
||||
import { fetchMeta } from "backend-rs";
|
||||
import { MAX_NOTE_TEXT_LENGTH, MAX_CAPTION_TEXT_LENGTH } from "@/const.js";
|
||||
import define from "@/server/api/define.js";
|
||||
|
||||
|
@ -466,7 +466,7 @@ export const paramDef = {
|
|||
} as const;
|
||||
|
||||
export default define(meta, paramDef, async () => {
|
||||
const instance = await fetchMeta(true);
|
||||
const instance = await fetchMeta(false);
|
||||
|
||||
return {
|
||||
maintainerName: instance.maintainerName,
|
||||
|
|
|
@ -1,8 +1,7 @@
|
|||
import define from "@/server/api/define.js";
|
||||
// import bcrypt from "bcryptjs";
|
||||
import rndstr from "rndstr";
|
||||
import { Users, UserProfiles } from "@/models/index.js";
|
||||
import { hashPassword } from "@/misc/password.js";
|
||||
import { hashPassword } from "backend-rs";
|
||||
|
||||
export const meta = {
|
||||
tags: ["admin"],
|
||||
|
@ -48,8 +47,7 @@ export default define(meta, paramDef, async (ps) => {
|
|||
const passwd = rndstr("a-zA-Z0-9", 8);
|
||||
|
||||
// Generate hash of password
|
||||
// const hash = bcrypt.hashSync(passwd);
|
||||
const hash = await hashPassword(passwd);
|
||||
const hash = hashPassword(passwd);
|
||||
|
||||
await UserProfiles.update(
|
||||
{
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
import { Users } from "@/models/index.js";
|
||||
import define from "@/server/api/define.js";
|
||||
import { sqlLikeEscape } from "@/misc/sql-like-escape.js";
|
||||
import { sqlLikeEscape } from "backend-rs";
|
||||
|
||||
export const meta = {
|
||||
tags: ["admin"],
|
||||
|
|
|
@ -2,7 +2,7 @@ import define from "@/server/api/define.js";
|
|||
import { Brackets } from "typeorm";
|
||||
import { makePaginationQuery } from "@/server/api/common/make-pagination-query.js";
|
||||
import { Channels } from "@/models/index.js";
|
||||
import { sqlLikeEscape } from "@/misc/sql-like-escape.js";
|
||||
import { sqlLikeEscape } from "backend-rs";
|
||||
|
||||
export const meta = {
|
||||
tags: ["channels"],
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
// import { IsNull } from 'typeorm';
|
||||
import { fetchMeta } from "@/misc/fetch-meta.js";
|
||||
import { fetchMeta } from "backend-rs";
|
||||
import define from "@/server/api/define.js";
|
||||
|
||||
export const meta = {
|
||||
|
@ -27,7 +27,7 @@ export const paramDef = {
|
|||
} as const;
|
||||
|
||||
export default define(meta, paramDef, async () => {
|
||||
const meta = await fetchMeta();
|
||||
const meta = await fetchMeta(true);
|
||||
const motd = await Promise.all(meta.customMotd.map((x) => x));
|
||||
return motd;
|
||||
});
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
// import { IsNull } from 'typeorm';
|
||||
import { fetchMeta } from "@/misc/fetch-meta.js";
|
||||
import { fetchMeta } from "backend-rs";
|
||||
import define from "@/server/api/define.js";
|
||||
|
||||
export const meta = {
|
||||
|
@ -27,7 +27,7 @@ export const paramDef = {
|
|||
} as const;
|
||||
|
||||
export default define(meta, paramDef, async () => {
|
||||
const meta = await fetchMeta();
|
||||
const meta = await fetchMeta(true);
|
||||
const icons = await Promise.all(meta.customSplashIcons.map((x) => x));
|
||||
return icons;
|
||||
});
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
import { fetchMeta } from "@/misc/fetch-meta.js";
|
||||
import { fetchMeta } from "backend-rs";
|
||||
import { DriveFiles } from "@/models/index.js";
|
||||
import define from "@/server/api/define.js";
|
||||
|
||||
|
@ -35,7 +35,7 @@ export const paramDef = {
|
|||
} as const;
|
||||
|
||||
export default define(meta, paramDef, async (ps, user) => {
|
||||
const instance = await fetchMeta(true);
|
||||
const instance = await fetchMeta(false);
|
||||
|
||||
// Calculate drive usage
|
||||
const usage = await DriveFiles.calcDriveUsageOf(user.id);
|
||||
|
|
|
@ -2,7 +2,7 @@ import { addFile } from "@/services/drive/add-file.js";
|
|||
import { DriveFiles } from "@/models/index.js";
|
||||
import { DB_MAX_IMAGE_COMMENT_LENGTH } from "@/misc/hard-limits.js";
|
||||
import { IdentifiableError } from "@/misc/identifiable-error.js";
|
||||
import { fetchMeta } from "@/misc/fetch-meta.js";
|
||||
import { fetchMeta } from "backend-rs";
|
||||
import { MINUTE } from "@/const.js";
|
||||
import define from "@/server/api/define.js";
|
||||
import { apiLogger } from "@/server/api/logger.js";
|
||||
|
@ -96,7 +96,7 @@ export default define(
|
|||
name = null;
|
||||
}
|
||||
|
||||
const instanceMeta = await fetchMeta();
|
||||
const instanceMeta = await fetchMeta(true);
|
||||
|
||||
try {
|
||||
// Create file
|
||||
|
|
|
@ -1,7 +1,6 @@
|
|||
import define from "@/server/api/define.js";
|
||||
import { Instances } from "@/models/index.js";
|
||||
import { fetchMeta } from "@/misc/fetch-meta.js";
|
||||
import { sqlLikeEscape } from "@/misc/sql-like-escape.js";
|
||||
import { fetchMeta, sqlLikeEscape } from "backend-rs";
|
||||
|
||||
export const meta = {
|
||||
tags: ["federation"],
|
||||
|
@ -101,7 +100,7 @@ export default define(meta, paramDef, async (ps, me) => {
|
|||
}
|
||||
|
||||
if (typeof ps.blocked === "boolean") {
|
||||
const meta = await fetchMeta(true);
|
||||
const meta = await fetchMeta(false);
|
||||
if (ps.blocked) {
|
||||
if (meta.blockedHosts.length === 0) {
|
||||
return [];
|
||||
|
@ -117,7 +116,7 @@ export default define(meta, paramDef, async (ps, me) => {
|
|||
}
|
||||
|
||||
if (typeof ps.silenced === "boolean") {
|
||||
const meta = await fetchMeta(true);
|
||||
const meta = await fetchMeta(false);
|
||||
if (ps.silenced) {
|
||||
if (meta.silencedHosts.length === 0) {
|
||||
return [];
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
import define from "@/server/api/define.js";
|
||||
import { Hashtags } from "@/models/index.js";
|
||||
import { sqlLikeEscape } from "@/misc/sql-like-escape.js";
|
||||
import { sqlLikeEscape } from "backend-rs";
|
||||
|
||||
export const meta = {
|
||||
tags: ["hashtags"],
|
||||
|
|
|
@ -1,9 +1,8 @@
|
|||
import { Brackets } from "typeorm";
|
||||
import define from "@/server/api/define.js";
|
||||
import { fetchMeta } from "@/misc/fetch-meta.js";
|
||||
import { fetchMeta, safeForSql } from "backend-rs";
|
||||
import { Notes } from "@/models/index.js";
|
||||
import type { Note } from "@/models/entities/note.js";
|
||||
import { safeForSql } from "@/misc/safe-for-sql.js";
|
||||
import { normalizeForSearch } from "@/misc/normalize-for-search.js";
|
||||
|
||||
/*
|
||||
|
@ -67,7 +66,7 @@ export const paramDef = {
|
|||
} as const;
|
||||
|
||||
export default define(meta, paramDef, async () => {
|
||||
const instance = await fetchMeta(true);
|
||||
const instance = await fetchMeta(false);
|
||||
const hiddenTags = instance.hiddenTags.map((t) => normalizeForSearch(t));
|
||||
|
||||
const now = new Date(); // 5分単位で丸めた現在日時
|
||||
|
|
|
@ -9,7 +9,7 @@ import {
|
|||
import config from "@/config/index.js";
|
||||
import { procedures, hash } from "@/server/api/2fa.js";
|
||||
import { publishMainStream } from "@/services/stream.js";
|
||||
import { comparePassword } from "@/misc/password.js";
|
||||
import { verifyPassword } from "backend-rs";
|
||||
|
||||
const rpIdHashReal = hash(Buffer.from(config.hostname, "utf-8"));
|
||||
|
||||
|
@ -40,8 +40,8 @@ export const paramDef = {
|
|||
export default define(meta, paramDef, async (ps, user) => {
|
||||
const profile = await UserProfiles.findOneByOrFail({ userId: user.id });
|
||||
|
||||
// Compare password
|
||||
const same = await comparePassword(ps.password, profile.password!);
|
||||
// Compare passwords
|
||||
const same = verifyPassword(ps.password, profile.password!);
|
||||
|
||||
if (!same) {
|
||||
throw new Error("incorrect password");
|
||||
|
|
|
@ -2,9 +2,8 @@ import define from "@/server/api/define.js";
|
|||
import { UserProfiles, AttestationChallenges } from "@/models/index.js";
|
||||
import { promisify } from "node:util";
|
||||
import * as crypto from "node:crypto";
|
||||
import { genId } from "backend-rs";
|
||||
import { genId, verifyPassword } from "backend-rs";
|
||||
import { hash } from "@/server/api/2fa.js";
|
||||
import { comparePassword } from "@/misc/password.js";
|
||||
|
||||
const randomBytes = promisify(crypto.randomBytes);
|
||||
|
||||
|
@ -25,8 +24,8 @@ export const paramDef = {
|
|||
export default define(meta, paramDef, async (ps, user) => {
|
||||
const profile = await UserProfiles.findOneByOrFail({ userId: user.id });
|
||||
|
||||
// Compare password
|
||||
const same = await comparePassword(ps.password, profile.password!);
|
||||
// Compare passwords
|
||||
const same = verifyPassword(ps.password, profile.password!);
|
||||
|
||||
if (!same) {
|
||||
throw new Error("incorrect password");
|
||||
|
|
|
@ -3,7 +3,7 @@ import * as QRCode from "qrcode";
|
|||
import config from "@/config/index.js";
|
||||
import { UserProfiles } from "@/models/index.js";
|
||||
import define from "@/server/api/define.js";
|
||||
import { comparePassword } from "@/misc/password.js";
|
||||
import { verifyPassword } from "backend-rs";
|
||||
|
||||
export const meta = {
|
||||
requireCredential: true,
|
||||
|
@ -22,8 +22,8 @@ export const paramDef = {
|
|||
export default define(meta, paramDef, async (ps, user) => {
|
||||
const profile = await UserProfiles.findOneByOrFail({ userId: user.id });
|
||||
|
||||
// Compare password
|
||||
const same = await comparePassword(ps.password, profile.password!);
|
||||
// Compare passwords
|
||||
const same = verifyPassword(ps.password, profile.password!);
|
||||
|
||||
if (!same) {
|
||||
throw new Error("incorrect password");
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
import { comparePassword } from "@/misc/password.js";
|
||||
import { verifyPassword } from "backend-rs";
|
||||
import define from "@/server/api/define.js";
|
||||
import { UserProfiles, UserSecurityKeys, Users } from "@/models/index.js";
|
||||
import { publishMainStream } from "@/services/stream.js";
|
||||
|
@ -21,8 +21,8 @@ export const paramDef = {
|
|||
export default define(meta, paramDef, async (ps, user) => {
|
||||
const profile = await UserProfiles.findOneByOrFail({ userId: user.id });
|
||||
|
||||
// Compare password
|
||||
const same = await comparePassword(ps.password, profile.password!);
|
||||
// Compare passwords
|
||||
const same = verifyPassword(ps.password, profile.password!);
|
||||
|
||||
if (!same) {
|
||||
throw new Error("incorrect password");
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
import { publishMainStream } from "@/services/stream.js";
|
||||
import define from "@/server/api/define.js";
|
||||
import { Users, UserProfiles } from "@/models/index.js";
|
||||
import { comparePassword } from "@/misc/password.js";
|
||||
import { verifyPassword } from "backend-rs";
|
||||
|
||||
export const meta = {
|
||||
requireCredential: true,
|
||||
|
@ -20,8 +20,8 @@ export const paramDef = {
|
|||
export default define(meta, paramDef, async (ps, user) => {
|
||||
const profile = await UserProfiles.findOneByOrFail({ userId: user.id });
|
||||
|
||||
// Compare password
|
||||
const same = await comparePassword(ps.password, profile.password!);
|
||||
// Compare passwords
|
||||
const same = verifyPassword(ps.password, profile.password!);
|
||||
|
||||
if (!same) {
|
||||
throw new Error("incorrect password");
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
import define from "@/server/api/define.js";
|
||||
import { UserProfiles } from "@/models/index.js";
|
||||
import { hashPassword, comparePassword } from "@/misc/password.js";
|
||||
import { hashPassword, verifyPassword } from "backend-rs";
|
||||
|
||||
export const meta = {
|
||||
requireCredential: true,
|
||||
|
@ -20,8 +20,8 @@ export const paramDef = {
|
|||
export default define(meta, paramDef, async (ps, user) => {
|
||||
const profile = await UserProfiles.findOneByOrFail({ userId: user.id });
|
||||
|
||||
// Compare password
|
||||
const same = await comparePassword(ps.currentPassword, profile.password!);
|
||||
// Compare passwords
|
||||
const same = verifyPassword(ps.currentPassword, profile.password!);
|
||||
|
||||
if (!same) {
|
||||
throw new Error("incorrect password");
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
import { UserProfiles, Users } from "@/models/index.js";
|
||||
import { deleteAccount } from "@/services/delete-account.js";
|
||||
import define from "@/server/api/define.js";
|
||||
import { comparePassword } from "@/misc/password.js";
|
||||
import { verifyPassword } from "backend-rs";
|
||||
|
||||
export const meta = {
|
||||
requireCredential: true,
|
||||
|
@ -24,8 +24,8 @@ export default define(meta, paramDef, async (ps, user) => {
|
|||
return;
|
||||
}
|
||||
|
||||
// Compare password
|
||||
const same = await comparePassword(ps.password, profile.password!);
|
||||
// Compare passwords
|
||||
const same = verifyPassword(ps.password, profile.password!);
|
||||
|
||||
if (!same) {
|
||||
throw new Error("incorrect password");
|
||||
|
|
|
@ -3,7 +3,7 @@ import { createImportPostsJob } from "@/queue/index.js";
|
|||
import { ApiError } from "@/server/api/error.js";
|
||||
import { DriveFiles } from "@/models/index.js";
|
||||
import { DAY } from "@/const.js";
|
||||
import { fetchMeta } from "@/misc/fetch-meta.js";
|
||||
import { fetchMeta } from "backend-rs";
|
||||
|
||||
export const meta = {
|
||||
secure: true,
|
||||
|
@ -45,7 +45,7 @@ export const paramDef = {
|
|||
export default define(meta, paramDef, async (ps, user) => {
|
||||
const file = await DriveFiles.findOneBy({ id: ps.fileId });
|
||||
|
||||
const instanceMeta = await fetchMeta();
|
||||
const instanceMeta = await fetchMeta(true);
|
||||
if (instanceMeta.experimentalFeatures?.postImports === false)
|
||||
throw new ApiError(meta.errors.importsDisabled);
|
||||
|
||||
|
|
|
@ -6,7 +6,7 @@ import {
|
|||
import generateUserToken from "@/server/api/common/generate-native-user-token.js";
|
||||
import define from "@/server/api/define.js";
|
||||
import { Users, UserProfiles } from "@/models/index.js";
|
||||
import { comparePassword } from "@/misc/password.js";
|
||||
import { verifyPassword } from "backend-rs";
|
||||
|
||||
export const meta = {
|
||||
requireCredential: true,
|
||||
|
@ -28,8 +28,8 @@ export default define(meta, paramDef, async (ps, user) => {
|
|||
|
||||
const profile = await UserProfiles.findOneByOrFail({ userId: user.id });
|
||||
|
||||
// Compare password
|
||||
const same = await comparePassword(ps.password, profile.password!);
|
||||
// Compare passwords
|
||||
const same = verifyPassword(ps.password, profile.password!);
|
||||
|
||||
if (!same) {
|
||||
throw new Error("incorrect password");
|
||||
|
|
|
@ -7,7 +7,7 @@ import { sendEmail } from "@/services/send-email.js";
|
|||
import { ApiError } from "@/server/api/error.js";
|
||||
import { validateEmailForAccount } from "@/services/validate-email-for-account.js";
|
||||
import { HOUR } from "@/const.js";
|
||||
import { comparePassword } from "@/misc/password.js";
|
||||
import { verifyPassword } from "backend-rs";
|
||||
|
||||
export const meta = {
|
||||
requireCredential: true,
|
||||
|
@ -46,8 +46,8 @@ export const paramDef = {
|
|||
export default define(meta, paramDef, async (ps, user) => {
|
||||
const profile = await UserProfiles.findOneByOrFail({ userId: user.id });
|
||||
|
||||
// Compare password
|
||||
const same = await comparePassword(ps.password, profile.password!);
|
||||
// Compare passwords
|
||||
const same = verifyPassword(ps.password, profile.password!);
|
||||
|
||||
if (!same) {
|
||||
throw new ApiError(meta.errors.incorrectPassword);
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
import JSON5 from "json5";
|
||||
import { IsNull, MoreThan } from "typeorm";
|
||||
import config from "@/config/index.js";
|
||||
import { fetchMeta } from "@/misc/fetch-meta.js";
|
||||
import { fetchMeta } from "backend-rs";
|
||||
import { Ads, Emojis, Users } from "@/models/index.js";
|
||||
import { MAX_NOTE_TEXT_LENGTH, MAX_CAPTION_TEXT_LENGTH } from "@/const.js";
|
||||
import define from "@/server/api/define.js";
|
||||
|
@ -398,7 +398,7 @@ export const paramDef = {
|
|||
} as const;
|
||||
|
||||
export default define(meta, paramDef, async (ps, me) => {
|
||||
const instance = await fetchMeta(true);
|
||||
const instance = await fetchMeta(false);
|
||||
|
||||
const emojis = await Emojis.find({
|
||||
where: {
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
import { fetchMeta } from "@/misc/fetch-meta.js";
|
||||
import { fetchMeta } from "backend-rs";
|
||||
import { Notes } from "@/models/index.js";
|
||||
import { activeUsersChart } from "@/services/chart/index.js";
|
||||
import define from "@/server/api/define.js";
|
||||
|
@ -64,7 +64,7 @@ export const paramDef = {
|
|||
} as const;
|
||||
|
||||
export default define(meta, paramDef, async (ps, user) => {
|
||||
const m = await fetchMeta();
|
||||
const m = await fetchMeta(true);
|
||||
if (m.disableGlobalTimeline) {
|
||||
if (user == null || !(user.isAdmin || user.isModerator)) {
|
||||
throw new ApiError(meta.errors.gtlDisabled);
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
import { Brackets } from "typeorm";
|
||||
import { fetchMeta } from "@/misc/fetch-meta.js";
|
||||
import { fetchMeta } from "backend-rs";
|
||||
import { Followings, Notes } from "@/models/index.js";
|
||||
import { activeUsersChart } from "@/services/chart/index.js";
|
||||
import define from "@/server/api/define.js";
|
||||
|
@ -71,7 +71,7 @@ export const paramDef = {
|
|||
} as const;
|
||||
|
||||
export default define(meta, paramDef, async (ps, user) => {
|
||||
const m = await fetchMeta();
|
||||
const m = await fetchMeta(true);
|
||||
if (m.disableLocalTimeline && !user.isAdmin && !user.isModerator) {
|
||||
throw new ApiError(meta.errors.stlDisabled);
|
||||
}
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
import { Brackets } from "typeorm";
|
||||
import { fetchMeta } from "@/misc/fetch-meta.js";
|
||||
import { fetchMeta } from "backend-rs";
|
||||
import { Notes } from "@/models/index.js";
|
||||
import { activeUsersChart } from "@/services/chart/index.js";
|
||||
import define from "@/server/api/define.js";
|
||||
|
@ -74,7 +74,7 @@ export const paramDef = {
|
|||
} as const;
|
||||
|
||||
export default define(meta, paramDef, async (ps, user) => {
|
||||
const m = await fetchMeta();
|
||||
const m = await fetchMeta(true);
|
||||
if (m.disableLocalTimeline) {
|
||||
if (user == null || !(user.isAdmin || user.isModerator)) {
|
||||
throw new ApiError(meta.errors.ltlDisabled);
|
||||
|
|
|
@ -53,7 +53,7 @@ export default define(meta, paramDef, async (ps, user) => {
|
|||
throw new ApiError(meta.errors.accessDenied);
|
||||
}
|
||||
|
||||
await deleteNote(user, note, false, false);
|
||||
await deleteNote(user, note, false);
|
||||
await Notes.update(note.id, {
|
||||
visibility: "specified",
|
||||
visibleUserIds: [],
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
import { Brackets } from "typeorm";
|
||||
import { fetchMeta } from "@/misc/fetch-meta.js";
|
||||
import { fetchMeta } from "backend-rs";
|
||||
import { Notes } from "@/models/index.js";
|
||||
import { activeUsersChart } from "@/services/chart/index.js";
|
||||
import define from "@/server/api/define.js";
|
||||
|
@ -74,7 +74,7 @@ export const paramDef = {
|
|||
} as const;
|
||||
|
||||
export default define(meta, paramDef, async (ps, user) => {
|
||||
const m = await fetchMeta();
|
||||
const m = await fetchMeta(true);
|
||||
if (m.disableRecommendedTimeline) {
|
||||
if (user == null || !(user.isAdmin || user.isModerator)) {
|
||||
throw new ApiError(meta.errors.rtlDisabled);
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
import { Brackets } from "typeorm";
|
||||
import { Notes } from "@/models/index.js";
|
||||
import { safeForSql } from "@/misc/safe-for-sql.js";
|
||||
import { safeForSql } from "backend-rs";
|
||||
import { normalizeForSearch } from "@/misc/normalize-for-search.js";
|
||||
import define from "@/server/api/define.js";
|
||||
import { makePaginationQuery } from "@/server/api/common/make-pagination-query.js";
|
||||
|
|
|
@ -1,11 +1,11 @@
|
|||
import { Notes } from "@/models/index.js";
|
||||
import { Note } from "@/models/entities/note.js";
|
||||
import type { Note } from "@/models/entities/note.js";
|
||||
import define from "@/server/api/define.js";
|
||||
import { makePaginationQuery } from "@/server/api/common/make-pagination-query.js";
|
||||
import { generateVisibilityQuery } from "@/server/api/common/generate-visibility-query.js";
|
||||
import { generateMutedUserQuery } from "@/server/api/common/generate-muted-user-query.js";
|
||||
import { generateBlockedUserQuery } from "@/server/api/common/generate-block-query.js";
|
||||
import { sqlLikeEscape } from "@/misc/sql-like-escape.js";
|
||||
import { sqlLikeEscape } from "backend-rs";
|
||||
import type { SelectQueryBuilder } from "typeorm";
|
||||
|
||||
export const meta = {
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
import { IsNull } from "typeorm";
|
||||
import { Users } from "@/models/index.js";
|
||||
import { fetchMeta } from "@/misc/fetch-meta.js";
|
||||
import { fetchMeta } from "backend-rs";
|
||||
import { stringToAcct } from "backend-rs";
|
||||
import type { User } from "@/models/entities/user.js";
|
||||
import define from "@/server/api/define.js";
|
||||
|
@ -31,7 +31,7 @@ export const paramDef = {
|
|||
} as const;
|
||||
|
||||
export default define(meta, paramDef, async (ps, me) => {
|
||||
const meta = await fetchMeta();
|
||||
const meta = await fetchMeta(true);
|
||||
|
||||
const users = await Promise.all(
|
||||
meta.pinnedUsers
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
// import { IsNull } from 'typeorm';
|
||||
import { fetchMeta } from "@/misc/fetch-meta.js";
|
||||
import { fetchMeta } from "backend-rs";
|
||||
import define from "@/server/api/define.js";
|
||||
|
||||
export const meta = {
|
||||
|
@ -27,7 +27,7 @@ export const paramDef = {
|
|||
} as const;
|
||||
|
||||
export default define(meta, paramDef, async () => {
|
||||
const meta = await fetchMeta();
|
||||
const meta = await fetchMeta(true);
|
||||
const instances = await Promise.all(meta.recommendedInstances.map((x) => x));
|
||||
return instances;
|
||||
});
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
import { UserProfiles, PasswordResetRequests } from "@/models/index.js";
|
||||
import define from "@/server/api/define.js";
|
||||
import { hashPassword } from "@/misc/password.js";
|
||||
import { hashPassword } from "backend-rs";
|
||||
|
||||
export const meta = {
|
||||
tags: ["reset password"],
|
||||
|
@ -32,7 +32,7 @@ export default define(meta, paramDef, async (ps, user) => {
|
|||
}
|
||||
|
||||
// Generate hash of password
|
||||
const hash = await hashPassword(ps.password);
|
||||
const hash = hashPassword(ps.password);
|
||||
|
||||
await UserProfiles.update(req.userId, {
|
||||
password: hash,
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
import * as os from "node:os";
|
||||
import si from "systeminformation";
|
||||
import define from "@/server/api/define.js";
|
||||
import { fetchMeta } from "@/misc/fetch-meta.js";
|
||||
import { fetchMeta } from "backend-rs";
|
||||
|
||||
export const meta = {
|
||||
requireCredential: false,
|
||||
|
@ -30,7 +30,7 @@ export default define(meta, paramDef, async () => {
|
|||
}
|
||||
}
|
||||
|
||||
const instanceMeta = await fetchMeta();
|
||||
const instanceMeta = await fetchMeta(true);
|
||||
if (!instanceMeta.enableServerMachineStats) {
|
||||
return {
|
||||
machine: "Not specified",
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
import { fetchMeta } from "@/misc/fetch-meta.js";
|
||||
import { fetchMeta } from "backend-rs";
|
||||
import { genId } from "backend-rs";
|
||||
import { SwSubscriptions } from "@/models/index.js";
|
||||
import define from "@/server/api/define.js";
|
||||
|
@ -64,7 +64,7 @@ export default define(meta, paramDef, async (ps, me) => {
|
|||
publickey: ps.publickey,
|
||||
});
|
||||
|
||||
const instance = await fetchMeta(true);
|
||||
const instance = await fetchMeta(false);
|
||||
|
||||
// if already subscribed
|
||||
if (subscription != null) {
|
||||
|
|
|
@ -4,7 +4,7 @@ import { publishAdminStream } from "@/services/stream.js";
|
|||
import { AbuseUserReports, UserProfiles, Users } from "@/models/index.js";
|
||||
import { genId } from "backend-rs";
|
||||
import { sendEmail } from "@/services/send-email.js";
|
||||
import { fetchMeta } from "@/misc/fetch-meta.js";
|
||||
import { fetchMeta } from "backend-rs";
|
||||
import { getUser } from "@/server/api/common/getters.js";
|
||||
import { ApiError } from "@/server/api/error.js";
|
||||
import define from "@/server/api/define.js";
|
||||
|
@ -86,7 +86,7 @@ export default define(meta, paramDef, async (ps, me) => {
|
|||
],
|
||||
});
|
||||
|
||||
const meta = await fetchMeta();
|
||||
const meta = await fetchMeta(true);
|
||||
for (const moderator of moderators) {
|
||||
publishAdminStream(moderator.id, "newAbuseUserReport", {
|
||||
id: report.id,
|
||||
|
|
|
@ -2,7 +2,7 @@ import { Brackets } from "typeorm";
|
|||
import { Followings, Users } from "@/models/index.js";
|
||||
import type { User } from "@/models/entities/user.js";
|
||||
import define from "@/server/api/define.js";
|
||||
import { sqlLikeEscape } from "@/misc/sql-like-escape.js";
|
||||
import { sqlLikeEscape } from "backend-rs";
|
||||
|
||||
export const meta = {
|
||||
tags: ["users"],
|
||||
|
|
|
@ -2,7 +2,7 @@ import { Brackets } from "typeorm";
|
|||
import { UserProfiles, Users } from "@/models/index.js";
|
||||
import type { User } from "@/models/entities/user.js";
|
||||
import define from "@/server/api/define.js";
|
||||
import { sqlLikeEscape } from "@/misc/sql-like-escape.js";
|
||||
import { sqlLikeEscape } from "backend-rs";
|
||||
|
||||
export const meta = {
|
||||
tags: ["users"],
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue