mirror of
https://github.com/AsamK/signal-cli.git
synced 2026-05-27 14:44:16 +00:00
Compare commits
15 Commits
8310b16895
...
f27eb524de
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
f27eb524de | ||
|
|
0006fd0dc0 | ||
|
|
417d2ce971 | ||
|
|
33b2b563b3 | ||
|
|
740cd6f89b | ||
|
|
7887ed408d | ||
|
|
ddfad2c4ce | ||
|
|
7e95ea7403 | ||
|
|
2991cdafe7 | ||
|
|
561dfc373f | ||
|
|
5bfb044245 | ||
|
|
e1b17bf863 | ||
|
|
72332750a8 | ||
|
|
aafb40fd94 | ||
|
|
7dc55eba81 |
57
.github/workflows/build.yml
vendored
Normal file
57
.github/workflows/build.yml
vendored
Normal file
@ -0,0 +1,57 @@
|
|||||||
|
name: build
|
||||||
|
|
||||||
|
on:
|
||||||
|
push:
|
||||||
|
branches:
|
||||||
|
- "**"
|
||||||
|
pull_request:
|
||||||
|
workflow_call:
|
||||||
|
|
||||||
|
permissions: {}
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
build:
|
||||||
|
strategy:
|
||||||
|
matrix:
|
||||||
|
# The "reproducible" entry is used to build the project with the LTS Java version used in reproducible builds script.
|
||||||
|
# More Java versions can be added to test compatibility, eg. "26".
|
||||||
|
java: ["reproducible", "26"]
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v6
|
||||||
|
- name: Build
|
||||||
|
run: |
|
||||||
|
if [ "${{ matrix.java }}" != "reproducible" ]; then
|
||||||
|
export OVERRIDE_JAVA_VERSION="${{ matrix.java }}"
|
||||||
|
fi
|
||||||
|
./reproducible-builds/build.sh
|
||||||
|
- name: Upload build artifacts
|
||||||
|
uses: actions/upload-artifact@v7
|
||||||
|
with:
|
||||||
|
name: signal-cli-${{ matrix.java }}-${{ github.job }}
|
||||||
|
path: dist/*
|
||||||
|
|
||||||
|
build-client:
|
||||||
|
strategy:
|
||||||
|
matrix:
|
||||||
|
os:
|
||||||
|
- ubuntu
|
||||||
|
- macos
|
||||||
|
- windows
|
||||||
|
runs-on: ${{ matrix.os }}-latest
|
||||||
|
defaults:
|
||||||
|
run:
|
||||||
|
working-directory: ./client
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v6
|
||||||
|
- name: Install rust
|
||||||
|
run: rustup default stable
|
||||||
|
- name: Build client
|
||||||
|
run: cargo build --release --verbose
|
||||||
|
- name: Archive production artifacts
|
||||||
|
uses: actions/upload-artifact@v7
|
||||||
|
with:
|
||||||
|
name: signal-cli-client-${{ matrix.os }}
|
||||||
|
path: |
|
||||||
|
client/target/release/signal-cli-client
|
||||||
|
client/target/release/signal-cli-client.exe
|
||||||
96
.github/workflows/ci.yml
vendored
96
.github/workflows/ci.yml
vendored
@ -1,96 +0,0 @@
|
|||||||
name: signal-cli CI
|
|
||||||
|
|
||||||
on:
|
|
||||||
push:
|
|
||||||
branches:
|
|
||||||
- '**'
|
|
||||||
pull_request:
|
|
||||||
workflow_call:
|
|
||||||
|
|
||||||
permissions:
|
|
||||||
contents: write # to fetch code (actions/checkout) and submit dependency graph (gradle/gradle-build-action)
|
|
||||||
|
|
||||||
jobs:
|
|
||||||
build:
|
|
||||||
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
strategy:
|
|
||||||
matrix:
|
|
||||||
java: [ '25', '26' ]
|
|
||||||
|
|
||||||
steps:
|
|
||||||
- uses: actions/checkout@v6
|
|
||||||
- name: Set up JDK
|
|
||||||
uses: actions/setup-java@v5
|
|
||||||
with:
|
|
||||||
distribution: 'zulu'
|
|
||||||
java-version: ${{ matrix.java }}
|
|
||||||
- name: Setup Gradle
|
|
||||||
uses: gradle/actions/setup-gradle@v5
|
|
||||||
with:
|
|
||||||
dependency-graph: generate-and-submit
|
|
||||||
- name: Install asciidoc
|
|
||||||
run: sudo apt update && sudo apt --no-install-recommends install -y asciidoc-base
|
|
||||||
- name: Build with Gradle
|
|
||||||
run: ./gradlew --no-daemon build
|
|
||||||
- name: Build man page
|
|
||||||
run: |
|
|
||||||
cd man
|
|
||||||
make install
|
|
||||||
- name: Add man page to archive
|
|
||||||
run: |
|
|
||||||
version=$(tar tf build/distributions/signal-cli-*.tar | head -n1 | sed 's|signal-cli-\([^/]*\)/.*|\1|')
|
|
||||||
echo $version
|
|
||||||
tar --transform="flags=r;s|man|signal-cli-${version}/man|" -rf build/distributions/signal-cli-${version}.tar man/man{1,5}
|
|
||||||
- name: Compress archive
|
|
||||||
run: gzip -n -9 build/distributions/signal-cli-*.tar
|
|
||||||
- name: Archive production artifacts
|
|
||||||
uses: actions/upload-artifact@v7
|
|
||||||
with:
|
|
||||||
name: signal-cli-archive-${{ matrix.java }}
|
|
||||||
path: build/distributions/signal-cli-*.tar.gz
|
|
||||||
|
|
||||||
build-graalvm:
|
|
||||||
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
|
|
||||||
steps:
|
|
||||||
- uses: actions/checkout@v6
|
|
||||||
- uses: graalvm/setup-graalvm@v1
|
|
||||||
with:
|
|
||||||
distribution: 'graalvm'
|
|
||||||
java-version: '25'
|
|
||||||
cache: 'gradle'
|
|
||||||
github-token: ${{ secrets.GITHUB_TOKEN }}
|
|
||||||
- name: Build with Gradle
|
|
||||||
run: ./gradlew --no-daemon nativeCompile
|
|
||||||
- name: Archive production artifacts
|
|
||||||
uses: actions/upload-artifact@v7
|
|
||||||
with:
|
|
||||||
name: signal-cli-native
|
|
||||||
path: build/native/nativeCompile/signal-cli
|
|
||||||
|
|
||||||
build-client:
|
|
||||||
strategy:
|
|
||||||
matrix:
|
|
||||||
os:
|
|
||||||
- ubuntu
|
|
||||||
- macos
|
|
||||||
- windows
|
|
||||||
runs-on: ${{ matrix.os }}-latest
|
|
||||||
defaults:
|
|
||||||
run:
|
|
||||||
working-directory: ./client
|
|
||||||
steps:
|
|
||||||
- uses: actions/checkout@v6
|
|
||||||
- name: Install rust
|
|
||||||
run: rustup default stable
|
|
||||||
- name: Build client
|
|
||||||
run: cargo build --release --verbose
|
|
||||||
- name: Archive production artifacts
|
|
||||||
uses: actions/upload-artifact@v7
|
|
||||||
with:
|
|
||||||
name: signal-cli-client-${{ matrix.os }}
|
|
||||||
path: |
|
|
||||||
client/target/release/signal-cli-client
|
|
||||||
client/target/release/signal-cli-client.exe
|
|
||||||
194
.github/workflows/release.yml
vendored
194
.github/workflows/release.yml
vendored
@ -5,8 +5,7 @@ on:
|
|||||||
tags:
|
tags:
|
||||||
- v*
|
- v*
|
||||||
|
|
||||||
permissions:
|
permissions: {}
|
||||||
contents: write # to fetch code (actions/checkout) and create release
|
|
||||||
|
|
||||||
env:
|
env:
|
||||||
IMAGE_NAME: signal-cli
|
IMAGE_NAME: signal-cli
|
||||||
@ -15,96 +14,25 @@ env:
|
|||||||
REGISTRY_PASSWORD: ${{ github.token }}
|
REGISTRY_PASSWORD: ${{ github.token }}
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
|
build:
|
||||||
|
uses: AsamK/signal-cli/.github/workflows/build.yml@master
|
||||||
|
|
||||||
ci_wf:
|
release:
|
||||||
permissions:
|
needs: build
|
||||||
contents: write
|
|
||||||
uses: AsamK/signal-cli/.github/workflows/ci.yml@master
|
|
||||||
# ${{ github.repository }} not accepted here
|
|
||||||
|
|
||||||
lib_to_jar:
|
|
||||||
needs: ci_wf
|
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
permissions:
|
permissions:
|
||||||
contents: write
|
contents: write
|
||||||
|
|
||||||
outputs:
|
outputs:
|
||||||
signal_cli_version: ${{ steps.cli_ver.outputs.version }}
|
version: ${{ steps.version.outputs.version }}
|
||||||
release_id: ${{ steps.create_release.outputs.id }}
|
|
||||||
|
|
||||||
steps:
|
steps:
|
||||||
|
|
||||||
- name: Download signal-cli build from CI workflow
|
- name: Download signal-cli build from CI workflow
|
||||||
uses: actions/download-artifact@v8
|
uses: actions/download-artifact@v8
|
||||||
|
|
||||||
- name: Get signal-cli version
|
- name: Get signal-cli version
|
||||||
id: cli_ver
|
id: version
|
||||||
run: |
|
run: |
|
||||||
ver="${GITHUB_REF_NAME#v}"
|
mv ./signal-cli-reproducible-build/* .
|
||||||
echo "version=${ver}" >> $GITHUB_OUTPUT
|
echo "version=$(cat VERSION)" >> $GITHUB_OUTPUT
|
||||||
|
|
||||||
- name: Extract archive
|
|
||||||
run: |
|
|
||||||
tree .
|
|
||||||
ARCHIVE_DIR=$(ls signal-cli-archive-*/ -d | tail -n1)
|
|
||||||
tar -xzf ./"${ARCHIVE_DIR}"/*.tar.gz
|
|
||||||
mv ./"${ARCHIVE_DIR}"/*.tar.gz signal-cli-${{ steps.cli_ver.outputs.version }}.tar.gz
|
|
||||||
rm -rf signal-cli-archive-*/
|
|
||||||
|
|
||||||
# - name: Get signal-client jar version
|
|
||||||
# id: lib_ver
|
|
||||||
# run: |
|
|
||||||
# JAR_PREFIX=libsignal-client-
|
|
||||||
# jar_file=$(find ./signal-cli-*/lib/ -name "$JAR_PREFIX*.jar")
|
|
||||||
# jar_version=$(echo "$jar_file" | xargs basename | sed "s/$JAR_PREFIX//; s/.jar//")
|
|
||||||
# echo "$jar_version"
|
|
||||||
# echo "signal_client_version=${jar_version}" >> $GITHUB_OUTPUT
|
|
||||||
#
|
|
||||||
# - name: Download signal-client builds
|
|
||||||
# env:
|
|
||||||
# RELEASES_URL: https://github.com/signalapp/libsignal/releases/download/
|
|
||||||
# FILE_NAMES: signal_jni.dll libsignal_jni.dylib
|
|
||||||
# SIGNAL_CLIENT_VER: ${{ steps.lib_ver.outputs.signal_client_version }}
|
|
||||||
# run: |
|
|
||||||
# for file_name in $FILE_NAMES; do
|
|
||||||
# curl -sOL "${RELEASES_URL}/v${SIGNAL_CLIENT_VER}/${file_name}" # note: added v
|
|
||||||
# done
|
|
||||||
# tree .
|
|
||||||
|
|
||||||
- name: Compress native app
|
|
||||||
env:
|
|
||||||
SIGNAL_CLI_VER: ${{ steps.cli_ver.outputs.version }}
|
|
||||||
run: |
|
|
||||||
chmod +x signal-cli-native/signal-cli
|
|
||||||
tar -czf signal-cli-${SIGNAL_CLI_VER}-Linux-native.tar.gz -C signal-cli-native signal-cli
|
|
||||||
rm -rf signal-cli-native/
|
|
||||||
|
|
||||||
- name: Compress client app
|
|
||||||
env:
|
|
||||||
SIGNAL_CLI_VER: ${{ steps.cli_ver.outputs.version }}
|
|
||||||
run: |
|
|
||||||
chmod +x signal-cli-client-ubuntu/signal-cli-client
|
|
||||||
tar -czf signal-cli-${SIGNAL_CLI_VER}-Linux-client.tar.gz -C signal-cli-client-ubuntu signal-cli-client
|
|
||||||
rm -rf signal-cli-client-ubuntu/
|
|
||||||
|
|
||||||
# - name: Replace Windows lib
|
|
||||||
# env:
|
|
||||||
# SIGNAL_CLI_VER: ${{ steps.cli_ver.outputs.version }}
|
|
||||||
# SIGNAL_CLIENT_VER: ${{ steps.lib_ver.outputs.signal_client_version }}
|
|
||||||
# run: |
|
|
||||||
# mv signal_jni.dll libsignal_jni.so
|
|
||||||
# zip -u ./signal-cli-*/lib/libsignal-client-${SIGNAL_CLIENT_VER}.jar ./libsignal_jni.so
|
|
||||||
# tar -czf signal-cli-${SIGNAL_CLI_VER}-Windows.tar.gz signal-cli-*/
|
|
||||||
#
|
|
||||||
# - name: Replace macOS lib
|
|
||||||
# env:
|
|
||||||
# SIGNAL_CLI_VER: ${{ steps.cli_ver.outputs.version }}
|
|
||||||
# SIGNAL_CLIENT_VER: ${{ steps.lib_ver.outputs.signal_client_version }}
|
|
||||||
# run: |
|
|
||||||
# jar_file=./signal-cli-*/lib/libsignal-client-${SIGNAL_CLIENT_VER}.jar
|
|
||||||
# zip -d $jar_file libsignal_jni.so
|
|
||||||
# zip $jar_file libsignal_jni.dylib
|
|
||||||
# tar -czf signal-cli-${SIGNAL_CLI_VER}-macOS.tar.gz signal-cli-*/
|
|
||||||
|
|
||||||
- name: Create release
|
- name: Create release
|
||||||
id: create_release
|
id: create_release
|
||||||
@ -112,8 +40,8 @@ jobs:
|
|||||||
env:
|
env:
|
||||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||||
with:
|
with:
|
||||||
tag_name: v${{ steps.cli_ver.outputs.version }} # note: added `v`
|
tag_name: v${{ steps.version.outputs.version }} # note: added `v`
|
||||||
release_name: v${{ steps.cli_ver.outputs.version }} # note: added `v`
|
release_name: v${{ steps.version.outputs.version }} # note: added `v`
|
||||||
draft: true
|
draft: true
|
||||||
|
|
||||||
- name: Upload archive
|
- name: Upload archive
|
||||||
@ -122,28 +50,18 @@ jobs:
|
|||||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||||
with:
|
with:
|
||||||
upload_url: ${{ steps.create_release.outputs.upload_url }}
|
upload_url: ${{ steps.create_release.outputs.upload_url }}
|
||||||
asset_path: signal-cli-${{ steps.cli_ver.outputs.version }}.tar.gz
|
asset_path: signal-cli-${{ steps.version.outputs.version }}.tar.gz
|
||||||
asset_name: signal-cli-${{ steps.cli_ver.outputs.version }}.tar.gz
|
asset_name: signal-cli-${{ steps.version.outputs.version }}.tar.gz
|
||||||
asset_content_type: application/x-compressed-tar # .tar.gz
|
asset_content_type: application/x-compressed-tar # .tar.gz
|
||||||
|
|
||||||
# - name: Upload Linux archive
|
|
||||||
# uses: actions/upload-release-asset@v1
|
|
||||||
# env:
|
|
||||||
# GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
|
||||||
# with:
|
|
||||||
# upload_url: ${{ steps.create_release.outputs.upload_url }}
|
|
||||||
# asset_path: signal-cli-${{ steps.cli_ver.outputs.version }}-Linux.tar.gz
|
|
||||||
# asset_name: signal-cli-${{ steps.cli_ver.outputs.version }}-Linux.tar.gz
|
|
||||||
# asset_content_type: application/x-compressed-tar # .tar.gz
|
|
||||||
|
|
||||||
- name: Upload Linux native archive
|
- name: Upload Linux native archive
|
||||||
uses: actions/upload-release-asset@v1
|
uses: actions/upload-release-asset@v1
|
||||||
env:
|
env:
|
||||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||||
with:
|
with:
|
||||||
upload_url: ${{ steps.create_release.outputs.upload_url }}
|
upload_url: ${{ steps.create_release.outputs.upload_url }}
|
||||||
asset_path: signal-cli-${{ steps.cli_ver.outputs.version }}-Linux-native.tar.gz
|
asset_path: signal-cli-${{ steps.version.outputs.version }}-Linux-native.tar.gz
|
||||||
asset_name: signal-cli-${{ steps.cli_ver.outputs.version }}-Linux-native.tar.gz
|
asset_name: signal-cli-${{ steps.version.outputs.version }}-Linux-native.tar.gz
|
||||||
asset_content_type: application/x-compressed-tar # .tar.gz
|
asset_content_type: application/x-compressed-tar # .tar.gz
|
||||||
|
|
||||||
- name: Upload Linux client archive
|
- name: Upload Linux client archive
|
||||||
@ -152,35 +70,14 @@ jobs:
|
|||||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||||
with:
|
with:
|
||||||
upload_url: ${{ steps.create_release.outputs.upload_url }}
|
upload_url: ${{ steps.create_release.outputs.upload_url }}
|
||||||
asset_path: signal-cli-${{ steps.cli_ver.outputs.version }}-Linux-client.tar.gz
|
asset_path: signal-cli-${{ steps.version.outputs.version }}-Linux-client.tar.gz
|
||||||
asset_name: signal-cli-${{ steps.cli_ver.outputs.version }}-Linux-client.tar.gz
|
asset_name: signal-cli-${{ steps.version.outputs.version }}-Linux-client.tar.gz
|
||||||
asset_content_type: application/x-compressed-tar # .tar.gz
|
asset_content_type: application/x-compressed-tar # .tar.gz
|
||||||
|
|
||||||
# - name: Upload windows archive
|
|
||||||
# uses: actions/upload-release-asset@v1
|
|
||||||
# env:
|
|
||||||
# GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
|
||||||
# with:
|
|
||||||
# upload_url: ${{ steps.create_release.outputs.upload_url }}
|
|
||||||
# asset_path: signal-cli-${{ steps.cli_ver.outputs.version }}-Windows.tar.gz
|
|
||||||
# asset_name: signal-cli-${{ steps.cli_ver.outputs.version }}-Windows.tar.gz
|
|
||||||
# asset_content_type: application/x-compressed-tar # .tar.gz
|
|
||||||
#
|
|
||||||
# - name: Upload macos archive
|
|
||||||
# uses: actions/upload-release-asset@v1
|
|
||||||
# env:
|
|
||||||
# GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
|
||||||
# with:
|
|
||||||
# upload_url: ${{ steps.create_release.outputs.upload_url }}
|
|
||||||
# asset_path: signal-cli-${{ steps.cli_ver.outputs.version }}-macOS.tar.gz
|
|
||||||
# asset_name: signal-cli-${{ steps.cli_ver.outputs.version }}-macOS.tar.gz
|
|
||||||
# asset_content_type: application/x-compressed-tar # .tar.gz
|
|
||||||
|
|
||||||
build-container:
|
build-container:
|
||||||
needs: ci_wf
|
needs: release
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
permissions:
|
permissions:
|
||||||
contents: read
|
|
||||||
packages: write
|
packages: write
|
||||||
|
|
||||||
steps:
|
steps:
|
||||||
@ -188,28 +85,19 @@ jobs:
|
|||||||
- name: Download signal-cli build from CI workflow
|
- name: Download signal-cli build from CI workflow
|
||||||
uses: actions/download-artifact@v8
|
uses: actions/download-artifact@v8
|
||||||
|
|
||||||
- name: Get signal-cli version
|
|
||||||
id: cli_ver
|
|
||||||
run: |
|
|
||||||
ver="${GITHUB_REF_NAME#v}"
|
|
||||||
echo "version=${ver}" >> $GITHUB_OUTPUT
|
|
||||||
|
|
||||||
- name: Move archive file
|
- name: Move archive file
|
||||||
run: |
|
run: |
|
||||||
ARCHIVE_DIR=$(ls signal-cli-archive-*/ -d | tail -n1)
|
tar xf ./signal-cli-reproducible-build/signal-cli-${{ needs.release.outputs.version }}.tar.gz
|
||||||
tar xf ./"${ARCHIVE_DIR}"/*.tar.gz
|
|
||||||
rm -r signal-cli-archive-* signal-cli-native
|
|
||||||
mkdir -p build/install/
|
mkdir -p build/install/
|
||||||
mv ./signal-cli-"${GITHUB_REF_NAME#v}"/ build/install/signal-cli
|
mv ./signal-cli-"${{ needs.release.outputs.version }}"/ build/install/signal-cli
|
||||||
|
|
||||||
- name: Build Image
|
- name: Build Image
|
||||||
id: build_image
|
id: build_image
|
||||||
uses: redhat-actions/buildah-build@v2
|
uses: redhat-actions/buildah-build@v2
|
||||||
with:
|
with:
|
||||||
image: ${{ env.IMAGE_NAME }}
|
image: ${{ env.IMAGE_NAME }}
|
||||||
tags: latest ${{ github.sha }} ${{ steps.cli_ver.outputs.version }}
|
tags: latest ${{ github.sha }} ${{ needs.release.outputs.version }}
|
||||||
containerfiles:
|
containerfiles: ./Containerfile
|
||||||
./Containerfile
|
|
||||||
oci: true
|
oci: true
|
||||||
|
|
||||||
- name: Push To GHCR
|
- name: Push To GHCR
|
||||||
@ -227,10 +115,9 @@ jobs:
|
|||||||
echo "${{ toJSON(steps.push.outputs) }}"
|
echo "${{ toJSON(steps.push.outputs) }}"
|
||||||
|
|
||||||
build-container-native:
|
build-container-native:
|
||||||
needs: ci_wf
|
needs: release
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
permissions:
|
permissions:
|
||||||
contents: read
|
|
||||||
packages: write
|
packages: write
|
||||||
|
|
||||||
steps:
|
steps:
|
||||||
@ -238,26 +125,20 @@ jobs:
|
|||||||
- name: Download signal-cli build from CI workflow
|
- name: Download signal-cli build from CI workflow
|
||||||
uses: actions/download-artifact@v8
|
uses: actions/download-artifact@v8
|
||||||
|
|
||||||
- name: Get signal-cli version
|
|
||||||
id: cli_ver
|
|
||||||
run: |
|
|
||||||
ver="${GITHUB_REF_NAME#v}"
|
|
||||||
echo "version=${ver}" >> $GITHUB_OUTPUT
|
|
||||||
|
|
||||||
- name: Move archive file
|
- name: Move archive file
|
||||||
run: |
|
run: |
|
||||||
|
tar xf ./signal-cli-reproducible-build/signal-cli-${{ needs.release.outputs.version }}-Linux-native.tar.gz
|
||||||
mkdir -p build/native/nativeCompile/
|
mkdir -p build/native/nativeCompile/
|
||||||
chmod +x ./signal-cli-native/signal-cli
|
mv signal-cli build/native/nativeCompile/
|
||||||
mv ./signal-cli-native/signal-cli build/native/nativeCompile/
|
chmod +x build/native/nativeCompile/signal-cli
|
||||||
|
|
||||||
- name: Build Image
|
- name: Build Image
|
||||||
id: build_image
|
id: build_image
|
||||||
uses: redhat-actions/buildah-build@v2
|
uses: redhat-actions/buildah-build@v2
|
||||||
with:
|
with:
|
||||||
image: ${{ env.IMAGE_NAME }}
|
image: ${{ env.IMAGE_NAME }}
|
||||||
tags: latest-native ${{ github.sha }}-native ${{ steps.cli_ver.outputs.version }}-native
|
tags: latest-native ${{ github.sha }}-native ${{ needs.release.outputs.version }}-native
|
||||||
containerfiles:
|
containerfiles: ./native.Containerfile
|
||||||
./native.Containerfile
|
|
||||||
oci: true
|
oci: true
|
||||||
|
|
||||||
- name: Push To GHCR
|
- name: Push To GHCR
|
||||||
@ -275,10 +156,9 @@ jobs:
|
|||||||
echo "${{ toJSON(steps.push.outputs) }}"
|
echo "${{ toJSON(steps.push.outputs) }}"
|
||||||
|
|
||||||
build-container-client:
|
build-container-client:
|
||||||
needs: ci_wf
|
needs: release
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
permissions:
|
permissions:
|
||||||
contents: read
|
|
||||||
packages: write
|
packages: write
|
||||||
|
|
||||||
steps:
|
steps:
|
||||||
@ -286,26 +166,20 @@ jobs:
|
|||||||
- name: Download signal-cli build from CI workflow
|
- name: Download signal-cli build from CI workflow
|
||||||
uses: actions/download-artifact@v8
|
uses: actions/download-artifact@v8
|
||||||
|
|
||||||
- name: Get signal-cli version
|
|
||||||
id: cli_ver
|
|
||||||
run: |
|
|
||||||
ver="${GITHUB_REF_NAME#v}"
|
|
||||||
echo "version=${ver}" >> $GITHUB_OUTPUT
|
|
||||||
|
|
||||||
- name: Move archive file
|
- name: Move archive file
|
||||||
run: |
|
run: |
|
||||||
|
tar xf ./signal-cli-reproducible-build/signal-cli-${{ needs.release.outputs.version }}-Linux-client.tar.gz
|
||||||
mkdir -p client/target/release/
|
mkdir -p client/target/release/
|
||||||
chmod +x ./signal-cli-client-ubuntu/signal-cli-client
|
mv signal-cli-client client/target/release/
|
||||||
mv ./signal-cli-client-ubuntu/signal-cli-client client/target/release/
|
chmod +x client/target/release/signal-cli-client
|
||||||
|
|
||||||
- name: Build Image
|
- name: Build Image
|
||||||
id: build_image
|
id: build_image
|
||||||
uses: redhat-actions/buildah-build@v2
|
uses: redhat-actions/buildah-build@v2
|
||||||
with:
|
with:
|
||||||
image: ${{ env.IMAGE_NAME }}
|
image: ${{ env.IMAGE_NAME }}
|
||||||
tags: latest-client ${{ github.sha }}-client ${{ steps.cli_ver.outputs.version }}-client
|
tags: latest-client ${{ github.sha }}-client ${{ needs.release.outputs.version }}-client
|
||||||
containerfiles:
|
containerfiles: ./client.Containerfile
|
||||||
./client.Containerfile
|
|
||||||
oci: true
|
oci: true
|
||||||
|
|
||||||
- name: Push To GHCR
|
- name: Push To GHCR
|
||||||
|
|||||||
7
.gitignore
vendored
7
.gitignore
vendored
@ -1,4 +1,5 @@
|
|||||||
.gradle/
|
.gradle/
|
||||||
|
.kotlin/
|
||||||
.idea/*
|
.idea/*
|
||||||
!.idea/codeStyles/
|
!.idea/codeStyles/
|
||||||
build/
|
build/
|
||||||
@ -13,3 +14,9 @@ out/
|
|||||||
.DS_Store
|
.DS_Store
|
||||||
/bin/
|
/bin/
|
||||||
/test-config/
|
/test-config/
|
||||||
|
/dist/
|
||||||
|
/github/
|
||||||
|
man/*.1
|
||||||
|
man/*.5
|
||||||
|
man/man1
|
||||||
|
man/man5
|
||||||
|
|||||||
@ -2,6 +2,10 @@
|
|||||||
|
|
||||||
## [Unreleased]
|
## [Unreleased]
|
||||||
|
|
||||||
|
### Changed
|
||||||
|
|
||||||
|
- Send message results now surface server-advised retry time for plain rate-limit (HTTP 413) failures, not only for proof-required challenges. The `retryAfterSeconds` field in JSON-RPC `SendMessageResult` is populated whenever the server sends a `Retry-After` header. The canonical way to distinguish proof-required failures remains `token != null`. Text output includes "retry after N seconds" when known.
|
||||||
|
|
||||||
## [0.14.2] - 2026-04-04
|
## [0.14.2] - 2026-04-04
|
||||||
|
|
||||||
### Added
|
### Added
|
||||||
|
|||||||
10
README.md
10
README.md
@ -148,6 +148,16 @@ version installed, you can replace `./gradlew` with `gradle` in the following st
|
|||||||
./gradlew run --args="--help"
|
./gradlew run --args="--help"
|
||||||
```
|
```
|
||||||
|
|
||||||
|
### JSON Schemas for the JSON-RPC mode
|
||||||
|
|
||||||
|
1. Generate [JSON Schema](https://json-schema.org/) files for all the JSON-RPC data classes (`src/main/java/org/asamk/signal/json`):
|
||||||
|
|
||||||
|
```sh
|
||||||
|
./gradlew jsonSchemas
|
||||||
|
```
|
||||||
|
|
||||||
|
2. The generated files can be found in the `build/generated/META-INF/schemas` folder.
|
||||||
|
|
||||||
### Building a native binary with GraalVM (EXPERIMENTAL)
|
### Building a native binary with GraalVM (EXPERIMENTAL)
|
||||||
|
|
||||||
It is possible to build a native binary with [GraalVM](https://www.graalvm.org). This is still experimental and will not
|
It is possible to build a native binary with [GraalVM](https://www.graalvm.org). This is still experimental and will not
|
||||||
|
|||||||
@ -1,3 +1,5 @@
|
|||||||
|
import groovy.json.JsonOutput
|
||||||
|
|
||||||
plugins {
|
plugins {
|
||||||
java
|
java
|
||||||
application
|
application
|
||||||
@ -72,6 +74,11 @@ val excludePatterns = mapOf(
|
|||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
|
||||||
|
val schemaAnnotationProcessor by configurations.creating {
|
||||||
|
isCanBeConsumed = false
|
||||||
|
isCanBeResolved = true
|
||||||
|
}
|
||||||
|
|
||||||
dependencies {
|
dependencies {
|
||||||
registerTransform(JarFileExcluder::class) {
|
registerTransform(JarFileExcluder::class) {
|
||||||
from.attribute(minified, false).attribute(artifactType, "jar")
|
from.attribute(minified, false).attribute(artifactType, "jar")
|
||||||
@ -82,6 +89,8 @@ dependencies {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
schemaAnnotationProcessor(libs.micronaut.json.schema.processor)
|
||||||
|
schemaAnnotationProcessor(libs.micronaut.inject.java)
|
||||||
implementation(libs.bouncycastle)
|
implementation(libs.bouncycastle)
|
||||||
implementation(libs.jackson.databind)
|
implementation(libs.jackson.databind)
|
||||||
implementation(libs.argparse4j)
|
implementation(libs.argparse4j)
|
||||||
@ -90,6 +99,10 @@ dependencies {
|
|||||||
implementation(libs.slf4j.jul)
|
implementation(libs.slf4j.jul)
|
||||||
implementation(libs.logback)
|
implementation(libs.logback)
|
||||||
implementation(libs.zxing)
|
implementation(libs.zxing)
|
||||||
|
implementation(libs.micronaut.json.schema.annotations)
|
||||||
|
if (gradle.startParameter.taskNames.any { it.contains("jsonSchemas") }) {
|
||||||
|
implementation(libs.micronaut.json.schema.generator)
|
||||||
|
}
|
||||||
implementation(project(":libsignal-cli"))
|
implementation(project(":libsignal-cli"))
|
||||||
|
|
||||||
testImplementation(libs.junit.jupiter)
|
testImplementation(libs.junit.jupiter)
|
||||||
@ -160,3 +173,30 @@ tasks.register("writeLibsignalVersion") {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
tasks.register<JavaCompile>("jsonSchemas") {
|
||||||
|
dependsOn(tasks.compileJava)
|
||||||
|
val schemaBaseUri = "http://localhost:8080/schemas/"
|
||||||
|
source = sourceSets.main.get().java
|
||||||
|
include("org/asamk/signal/json/**/*.java")
|
||||||
|
classpath = sourceSets.main.get().compileClasspath + files(sourceSets.main.get().java.destinationDirectory)
|
||||||
|
destinationDirectory.set(layout.buildDirectory.dir("generated"))
|
||||||
|
options.annotationProcessorPath = schemaAnnotationProcessor
|
||||||
|
options.compilerArgs.addAll(
|
||||||
|
listOf(
|
||||||
|
"-Amicronaut.processing.group=org.asamk",
|
||||||
|
"-Amicronaut.processing.module=signal-cli",
|
||||||
|
"-Amicronaut.processing.annotations=org.asamk.signal.json.*",
|
||||||
|
"-Amicronaut.jsonschema.baseUri=$schemaBaseUri",
|
||||||
|
)
|
||||||
|
)
|
||||||
|
doLast {
|
||||||
|
fileTree(destinationDirectory.get().dir("META-INF/schemas").asFile) {
|
||||||
|
include("*.schema.json")
|
||||||
|
}.forEach { schemaFile ->
|
||||||
|
val normalized = schemaFile.readText().replace("\"$schemaBaseUri/", "\"")
|
||||||
|
val prettyJson = JsonOutput.prettyPrint(normalized)
|
||||||
|
schemaFile.writeText("$prettyJson\n")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
323
client/Cargo.lock
generated
323
client/Cargo.lock
generated
@ -4,9 +4,9 @@ version = 4
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "anstream"
|
name = "anstream"
|
||||||
version = "0.6.21"
|
version = "1.0.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "43d5b281e737544384e969a5ccad3f1cdd24b48086a0fc1b2a5262a26b8f4f4a"
|
checksum = "824a212faf96e9acacdbd09febd34438f8f711fb84e09a8916013cd7815ca28d"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"anstyle",
|
"anstyle",
|
||||||
"anstyle-parse",
|
"anstyle-parse",
|
||||||
@ -19,15 +19,15 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "anstyle"
|
name = "anstyle"
|
||||||
version = "1.0.13"
|
version = "1.0.14"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "5192cca8006f1fd4f7237516f40fa183bb07f8fbdfedaa0036de5ea9b0b45e78"
|
checksum = "940b3a0ca603d1eade50a4846a2afffd5ef57a9feac2c0e2ec2e14f9ead76000"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "anstyle-parse"
|
name = "anstyle-parse"
|
||||||
version = "0.2.7"
|
version = "1.0.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "4e7644824f0aa2c7b9384579234ef10eb7efb6a0deb83f9630a49594dd9c15c2"
|
checksum = "52ce7f38b242319f7cabaa6813055467063ecdc9d355bbb4ce0c68908cd8130e"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"utf8parse",
|
"utf8parse",
|
||||||
]
|
]
|
||||||
@ -83,9 +83,9 @@ checksum = "72b3254f16251a8381aa12e40e3c4d2f0199f8c6508fbecb9d91f575e0fbb8c6"
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "bitflags"
|
name = "bitflags"
|
||||||
version = "2.11.0"
|
version = "2.11.1"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "843867be96c8daad0d758b57df9392b6d8d271134fce549de6ce169ff98a92af"
|
checksum = "c4512299f36f043ab09a583e57bceb5a5aab7a73db1805848e8fef3c9e8c78b3"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "bytes"
|
name = "bytes"
|
||||||
@ -95,9 +95,9 @@ checksum = "1e748733b7cbc798e1434b6ac524f0c1ff2ab456fe201501e6497c8417a4fc33"
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "cc"
|
name = "cc"
|
||||||
version = "1.2.56"
|
version = "1.2.60"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "aebf35691d1bfb0ac386a69bac2fde4dd276fb618cf8bf4f5318fe285e821bb2"
|
checksum = "43c5703da9466b66a946814e1adf53ea2c90f10063b86290cc9eb67ce3478a20"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"find-msvc-tools",
|
"find-msvc-tools",
|
||||||
"shlex",
|
"shlex",
|
||||||
@ -117,9 +117,9 @@ checksum = "9330f8b2ff13f34540b44e946ef35111825727b38d33286ef986142615121801"
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "clap"
|
name = "clap"
|
||||||
version = "4.5.60"
|
version = "4.6.1"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "2797f34da339ce31042b27d23607e051786132987f595b02ba4f6a6dffb7030a"
|
checksum = "1ddb117e43bbf7dacf0a4190fef4d345b9bad68dfc649cb349e7d17d28428e51"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"clap_builder",
|
"clap_builder",
|
||||||
"clap_derive",
|
"clap_derive",
|
||||||
@ -127,9 +127,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "clap_builder"
|
name = "clap_builder"
|
||||||
version = "4.5.60"
|
version = "4.6.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "24a241312cea5059b13574bb9b3861cabf758b879c15190b37b6d6fd63ab6876"
|
checksum = "714a53001bf66416adb0e2ef5ac857140e7dc3a0c48fb28b2f10762fc4b5069f"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"anstream",
|
"anstream",
|
||||||
"anstyle",
|
"anstyle",
|
||||||
@ -140,9 +140,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "clap_derive"
|
name = "clap_derive"
|
||||||
version = "4.5.55"
|
version = "4.6.1"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "a92793da1a46a5f2a02a6f4c46c6496b28c43638adea8306fcb0caa1634f24e5"
|
checksum = "f2ce8604710f6733aa641a2b3731eaa1e8b3d9973d5e3565da11800813f997a9"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"heck",
|
"heck",
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
@ -152,15 +152,15 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "clap_lex"
|
name = "clap_lex"
|
||||||
version = "1.0.0"
|
version = "1.1.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "3a822ea5bc7590f9d40f1ba12c0dc3c2760f3482c6984db1573ad11031420831"
|
checksum = "c8d4a3bb8b1e0c1050499d1815f5ab16d04f0959b233085fb31653fbfc9d98f9"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "colorchoice"
|
name = "colorchoice"
|
||||||
version = "1.0.4"
|
version = "1.0.5"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "b05b61dc5112cbb17e4b6cd61790d9845d13888356391624cbe7e41efeac1e75"
|
checksum = "1d07550c9036bf2ae0c684c4297d503f838287c83c53686d05370d0e139ae570"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "combine"
|
name = "combine"
|
||||||
@ -326,9 +326,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "hashbrown"
|
name = "hashbrown"
|
||||||
version = "0.16.1"
|
version = "0.17.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "841d1cc9bed7f9236f321df977030373f4a4163ae1a7dbfe1a51a2c1a51d9100"
|
checksum = "4f467dd6dccf739c208452f8014c75c18bb8301b050ad1cfb27153803edb0f51"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "heck"
|
name = "heck"
|
||||||
@ -377,9 +377,9 @@ checksum = "6dbf3de79e51f3d586ab4cb9d5c3e2c14aa28ed23d180cf89b4df0454a69cc87"
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "hyper"
|
name = "hyper"
|
||||||
version = "1.8.1"
|
version = "1.9.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "2ab2d4f250c3d7b1c9fcdff1cece94ea4e2dfbec68614f7b87cb205f24ca9d11"
|
checksum = "6299f016b246a94207e63da54dbe807655bf9e00044f73ded42c3ac5305fbcca"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"atomic-waker",
|
"atomic-waker",
|
||||||
"bytes",
|
"bytes",
|
||||||
@ -391,7 +391,6 @@ dependencies = [
|
|||||||
"httparse",
|
"httparse",
|
||||||
"itoa",
|
"itoa",
|
||||||
"pin-project-lite",
|
"pin-project-lite",
|
||||||
"pin-utils",
|
|
||||||
"smallvec",
|
"smallvec",
|
||||||
"tokio",
|
"tokio",
|
||||||
"want",
|
"want",
|
||||||
@ -399,16 +398,15 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "hyper-rustls"
|
name = "hyper-rustls"
|
||||||
version = "0.27.7"
|
version = "0.27.9"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "e3c93eb611681b207e1fe55d5a71ecf91572ec8a6705cdb6857f7d8d5242cf58"
|
checksum = "33ca68d021ef39cf6463ab54c1d0f5daf03377b70561305bb89a8f83aab66e0f"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"http",
|
"http",
|
||||||
"hyper",
|
"hyper",
|
||||||
"hyper-util",
|
"hyper-util",
|
||||||
"log",
|
"log",
|
||||||
"rustls",
|
"rustls",
|
||||||
"rustls-pki-types",
|
|
||||||
"tokio",
|
"tokio",
|
||||||
"tokio-rustls",
|
"tokio-rustls",
|
||||||
"tower-service",
|
"tower-service",
|
||||||
@ -436,12 +434,13 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "icu_collections"
|
name = "icu_collections"
|
||||||
version = "2.1.1"
|
version = "2.2.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "4c6b649701667bbe825c3b7e6388cb521c23d88644678e83c0c4d0a621a34b43"
|
checksum = "2984d1cd16c883d7935b9e07e44071dca8d917fd52ecc02c04d5fa0b5a3f191c"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"displaydoc",
|
"displaydoc",
|
||||||
"potential_utf",
|
"potential_utf",
|
||||||
|
"utf8_iter",
|
||||||
"yoke",
|
"yoke",
|
||||||
"zerofrom",
|
"zerofrom",
|
||||||
"zerovec",
|
"zerovec",
|
||||||
@ -449,9 +448,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "icu_locale_core"
|
name = "icu_locale_core"
|
||||||
version = "2.1.1"
|
version = "2.2.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "edba7861004dd3714265b4db54a3c390e880ab658fec5f7db895fae2046b5bb6"
|
checksum = "92219b62b3e2b4d88ac5119f8904c10f8f61bf7e95b640d25ba3075e6cac2c29"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"displaydoc",
|
"displaydoc",
|
||||||
"litemap",
|
"litemap",
|
||||||
@ -462,9 +461,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "icu_normalizer"
|
name = "icu_normalizer"
|
||||||
version = "2.1.1"
|
version = "2.2.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "5f6c8828b67bf8908d82127b2054ea1b4427ff0230ee9141c54251934ab1b599"
|
checksum = "c56e5ee99d6e3d33bd91c5d85458b6005a22140021cc324cea84dd0e72cff3b4"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"icu_collections",
|
"icu_collections",
|
||||||
"icu_normalizer_data",
|
"icu_normalizer_data",
|
||||||
@ -476,15 +475,15 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "icu_normalizer_data"
|
name = "icu_normalizer_data"
|
||||||
version = "2.1.1"
|
version = "2.2.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "7aedcccd01fc5fe81e6b489c15b247b8b0690feb23304303a9e560f37efc560a"
|
checksum = "da3be0ae77ea334f4da67c12f149704f19f81d1adf7c51cf482943e84a2bad38"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "icu_properties"
|
name = "icu_properties"
|
||||||
version = "2.1.2"
|
version = "2.2.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "020bfc02fe870ec3a66d93e677ccca0562506e5872c650f893269e08615d74ec"
|
checksum = "bee3b67d0ea5c2cca5003417989af8996f8604e34fb9ddf96208a033901e70de"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"icu_collections",
|
"icu_collections",
|
||||||
"icu_locale_core",
|
"icu_locale_core",
|
||||||
@ -496,15 +495,15 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "icu_properties_data"
|
name = "icu_properties_data"
|
||||||
version = "2.1.2"
|
version = "2.2.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "616c294cf8d725c6afcd8f55abc17c56464ef6211f9ed59cccffe534129c77af"
|
checksum = "8e2bbb201e0c04f7b4b3e14382af113e17ba4f63e2c9d2ee626b720cbce54a14"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "icu_provider"
|
name = "icu_provider"
|
||||||
version = "2.1.1"
|
version = "2.2.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "85962cf0ce02e1e0a629cc34e7ca3e373ce20dda4c4d7294bbd0bf1fdb59e614"
|
checksum = "139c4cf31c8b5f33d7e199446eff9c1e02decfc2f0eec2c8d71f65befa45b421"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"displaydoc",
|
"displaydoc",
|
||||||
"icu_locale_core",
|
"icu_locale_core",
|
||||||
@ -538,9 +537,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "indexmap"
|
name = "indexmap"
|
||||||
version = "2.13.0"
|
version = "2.14.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "7714e70437a7dc3ac8eb7e6f8df75fd8eb422675fc7678aff7364301092b1017"
|
checksum = "d466e9454f08e4a911e14806c24e16fba1b4c121d1ea474396f396069cf949d9"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"equivalent",
|
"equivalent",
|
||||||
"hashbrown",
|
"hashbrown",
|
||||||
@ -554,9 +553,9 @@ checksum = "a6cb138bb79a146c1bd460005623e142ef0181e3d0219cb493e02f7d08a35695"
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "itoa"
|
name = "itoa"
|
||||||
version = "1.0.17"
|
version = "1.0.18"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "92ecc6618181def0457392ccd0ee51198e065e016d1d527a7ac1b6dc7c1f09d2"
|
checksum = "8f42a60cbdf9a97f5d2305f08a87dc4e09308d1276d28c869c684d7777685682"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "jni"
|
name = "jni"
|
||||||
@ -567,7 +566,7 @@ dependencies = [
|
|||||||
"cesu8",
|
"cesu8",
|
||||||
"cfg-if",
|
"cfg-if",
|
||||||
"combine",
|
"combine",
|
||||||
"jni-sys",
|
"jni-sys 0.3.1",
|
||||||
"log",
|
"log",
|
||||||
"thiserror 1.0.69",
|
"thiserror 1.0.69",
|
||||||
"walkdir",
|
"walkdir",
|
||||||
@ -576,9 +575,31 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "jni-sys"
|
name = "jni-sys"
|
||||||
version = "0.3.0"
|
version = "0.3.1"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "8eaf4bc02d17cbdd7ff4c7438cafcdf7fb9a4613313ad11b4f8fefe7d3fa0130"
|
checksum = "41a652e1f9b6e0275df1f15b32661cf0d4b78d4d87ddec5e0c3c20f097433258"
|
||||||
|
dependencies = [
|
||||||
|
"jni-sys 0.4.1",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "jni-sys"
|
||||||
|
version = "0.4.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "c6377a88cb3910bee9b0fa88d4f42e1d2da8e79915598f65fb0c7ee14c878af2"
|
||||||
|
dependencies = [
|
||||||
|
"jni-sys-macros",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "jni-sys-macros"
|
||||||
|
version = "0.4.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "38c0b942f458fe50cdac086d2f946512305e5631e720728f2a61aabcd47a6264"
|
||||||
|
dependencies = [
|
||||||
|
"quote",
|
||||||
|
"syn",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "jsonrpsee"
|
name = "jsonrpsee"
|
||||||
@ -668,9 +689,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "libc"
|
name = "libc"
|
||||||
version = "0.2.182"
|
version = "0.2.185"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "6800badb6cb2082ffd7b6a67e6125bb39f18782f793520caee8cb8846be06112"
|
checksum = "52ff2c0fe9bc6cb6b14a0592c2ff4fa9ceb83eea9db979b0487cd054946a2b8f"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "linux-raw-sys"
|
name = "linux-raw-sys"
|
||||||
@ -680,9 +701,9 @@ checksum = "32a66949e030da00e8c7d4434b251670a91556f4144941d37452769c25d58a53"
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "litemap"
|
name = "litemap"
|
||||||
version = "0.8.1"
|
version = "0.8.2"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "6373607a59f0be73a39b6fe456b8192fcc3585f602af20751600e974dd455e77"
|
checksum = "92daf443525c4cce67b150400bc2316076100ce0b3686209eb8cf3c31612e6f0"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "log"
|
name = "log"
|
||||||
@ -698,9 +719,9 @@ checksum = "f8ca58f447f06ed17d5fc4043ce1b10dd205e060fb3ce5b979b8ed8e59ff3f79"
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "mio"
|
name = "mio"
|
||||||
version = "1.1.1"
|
version = "1.2.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "a69bcab0ad47271a0234d9422b131806bf3968021e5dc9328caf2d4cd58557fc"
|
checksum = "50b7e5b27aa02a74bac8c3f23f448f8d87ff11f92d3aac1a6ed369ee08cc56c1"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"libc",
|
"libc",
|
||||||
"wasi",
|
"wasi",
|
||||||
@ -709,9 +730,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "once_cell"
|
name = "once_cell"
|
||||||
version = "1.21.3"
|
version = "1.21.4"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "42f5e15c9953c5e4ccceeb2e7382a716482c34515315f7b03532b8b4e8393d2d"
|
checksum = "9f7c3e4beb33f85d45ae3e3a1792185706c8e16d043238c593331cc7cd313b50"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "once_cell_polyfill"
|
name = "once_cell_polyfill"
|
||||||
@ -757,26 +778,20 @@ version = "0.2.17"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "a89322df9ebe1c1578d689c92318e070967d1042b512afbe49518723f4e6d5cd"
|
checksum = "a89322df9ebe1c1578d689c92318e070967d1042b512afbe49518723f4e6d5cd"
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "pin-utils"
|
|
||||||
version = "0.1.0"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184"
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "potential_utf"
|
name = "potential_utf"
|
||||||
version = "0.1.4"
|
version = "0.1.5"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "b73949432f5e2a09657003c25bca5e19a0e9c84f8058ca374f49e0ebe605af77"
|
checksum = "0103b1cef7ec0cf76490e969665504990193874ea05c85ff9bab8b911d0a0564"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"zerovec",
|
"zerovec",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "proc-macro-crate"
|
name = "proc-macro-crate"
|
||||||
version = "3.4.0"
|
version = "3.5.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "219cb19e96be00ab2e37d6e299658a0cfa83e52429179969b0f0121b4ac46983"
|
checksum = "e67ba7e9b2b56446f1d419b1d807906278ffa1a658a8a5d8a39dcb1f5a78614f"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"toml_edit",
|
"toml_edit",
|
||||||
]
|
]
|
||||||
@ -792,9 +807,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "quote"
|
name = "quote"
|
||||||
version = "1.0.44"
|
version = "1.0.45"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "21b2ebcf727b7760c461f091f9f0f539b77b8e87f2fd88131e7f1b433b3cece4"
|
checksum = "41f2619966050689382d2b44f664f4bc593e129785a36d6ee376ddf37259b924"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
]
|
]
|
||||||
@ -815,9 +830,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "rustc-hash"
|
name = "rustc-hash"
|
||||||
version = "2.1.1"
|
version = "2.1.2"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "357703d41365b4b27c590e3ed91eabb1b663f07c4c084095e60cbed4362dff0d"
|
checksum = "94300abf3f1ae2e2b8ffb7b58043de3d399c73fa6f4b73826402a5c457614dbe"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "rustix"
|
name = "rustix"
|
||||||
@ -834,9 +849,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "rustls"
|
name = "rustls"
|
||||||
version = "0.23.37"
|
version = "0.23.38"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "758025cb5fccfd3bc2fd74708fd4682be41d99e5dff73c377c0646c6012c73a4"
|
checksum = "69f9466fb2c14ea04357e91413efb882e2a6d4a406e625449bc0a5d360d53a21"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"log",
|
"log",
|
||||||
"once_cell",
|
"once_cell",
|
||||||
@ -897,9 +912,9 @@ checksum = "f87165f0995f63a9fbeea62b64d10b4d9d8e78ec6d7d51fb2125fda7bb36788f"
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "rustls-webpki"
|
name = "rustls-webpki"
|
||||||
version = "0.103.10"
|
version = "0.103.12"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "df33b2b81ac578cabaf06b89b0631153a3f416b0a886e8a7a1707fb51abbd1ef"
|
checksum = "8279bb85272c9f10811ae6a6c547ff594d6a7f3c6c6b02ee9726d1d0dcfcdd06"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"ring",
|
"ring",
|
||||||
"rustls-pki-types",
|
"rustls-pki-types",
|
||||||
@ -917,9 +932,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "schannel"
|
name = "schannel"
|
||||||
version = "0.1.28"
|
version = "0.1.29"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "891d81b926048e76efe18581bf793546b4c0eaf8448d72be8de2bbee5fd166e1"
|
checksum = "91c1b7e4904c873ef0710c1f407dde2e6287de2bebc1bbbf7d430bb7cbffd939"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"windows-sys 0.61.2",
|
"windows-sys 0.61.2",
|
||||||
]
|
]
|
||||||
@ -1026,12 +1041,12 @@ checksum = "67b1b7a3b5fe4f1376887184045fcf45c69e92af734b7aaddc05fb777b6fbd03"
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "socket2"
|
name = "socket2"
|
||||||
version = "0.6.2"
|
version = "0.6.3"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "86f4aa3ad99f2088c990dfa82d367e19cb29268ed67c574d10d0a4bfe71f07e0"
|
checksum = "3a766e1110788c36f4fa1c2b71b387a7815aa65f88ce0229841826633d93723e"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"libc",
|
"libc",
|
||||||
"windows-sys 0.60.2",
|
"windows-sys 0.61.2",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@ -1082,12 +1097,12 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "terminal_size"
|
name = "terminal_size"
|
||||||
version = "0.4.3"
|
version = "0.4.4"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "60b8cb979cb11c32ce1603f8137b22262a9d131aaa5c37b5678025f22b8becd0"
|
checksum = "230a1b821ccbd75b185820a1f1ff7b14d21da1e442e22c0863ea5f08771a8874"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"rustix",
|
"rustix",
|
||||||
"windows-sys 0.60.2",
|
"windows-sys 0.61.2",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@ -1132,9 +1147,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "tinystr"
|
name = "tinystr"
|
||||||
version = "0.8.2"
|
version = "0.8.3"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "42d3e9c45c09de15d06dd8acf5f4e0e399e85927b7f00711024eb7ae10fa4869"
|
checksum = "c8323304221c2a851516f22236c5722a72eaa19749016521d6dff0824447d96d"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"displaydoc",
|
"displaydoc",
|
||||||
"zerovec",
|
"zerovec",
|
||||||
@ -1142,9 +1157,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "tokio"
|
name = "tokio"
|
||||||
version = "1.49.0"
|
version = "1.52.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "72a2903cd7736441aac9df9d7688bd0ce48edccaadf181c3b90be801e81d3d86"
|
checksum = "a91135f59b1cbf38c91e73cf3386fca9bb77915c45ce2771460c9d92f0f3d776"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"bytes",
|
"bytes",
|
||||||
"libc",
|
"libc",
|
||||||
@ -1157,9 +1172,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "tokio-macros"
|
name = "tokio-macros"
|
||||||
version = "2.6.0"
|
version = "2.7.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "af407857209536a95c8e56f8231ef2c2e2aff839b22e07a1ffcbc617e9db9fa5"
|
checksum = "385a6cb71ab9ab790c5fe8d67f1645e6c450a7ce006a33de03daa956cf70a496"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"quote",
|
"quote",
|
||||||
@ -1202,18 +1217,18 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "toml_datetime"
|
name = "toml_datetime"
|
||||||
version = "0.7.5+spec-1.1.0"
|
version = "1.1.1+spec-1.1.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "92e1cfed4a3038bc5a127e35a2d360f145e1f4b971b551a2ba5fd7aedf7e1347"
|
checksum = "3165f65f62e28e0115a00b2ebdd37eb6f3b641855f9d636d3cd4103767159ad7"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"serde_core",
|
"serde_core",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "toml_edit"
|
name = "toml_edit"
|
||||||
version = "0.23.10+spec-1.0.0"
|
version = "0.25.11+spec-1.1.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "84c8b9f757e028cee9fa244aea147aab2a9ec09d5325a9b01e0a49730c2b5269"
|
checksum = "0b59c4d22ed448339746c59b905d24568fcbb3ab65a500494f7b8c3e97739f2b"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"indexmap",
|
"indexmap",
|
||||||
"toml_datetime",
|
"toml_datetime",
|
||||||
@ -1223,9 +1238,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "toml_parser"
|
name = "toml_parser"
|
||||||
version = "1.0.9+spec-1.1.0"
|
version = "1.1.2+spec-1.1.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "702d4415e08923e7e1ef96cd5727c0dfed80b4d2fa25db9647fe5eb6f7c5a4c4"
|
checksum = "a2abe9b86193656635d2411dc43050282ca48aa31c2451210f4202550afb7526"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"winnow",
|
"winnow",
|
||||||
]
|
]
|
||||||
@ -1360,14 +1375,14 @@ version = "0.26.11"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "75c7f0ef91146ebfb530314f5f1d24528d7f0767efbfd31dce919275413e393e"
|
checksum = "75c7f0ef91146ebfb530314f5f1d24528d7f0767efbfd31dce919275413e393e"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"webpki-root-certs 1.0.6",
|
"webpki-root-certs 1.0.7",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "webpki-root-certs"
|
name = "webpki-root-certs"
|
||||||
version = "1.0.6"
|
version = "1.0.7"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "804f18a4ac2676ffb4e8b5b5fa9ae38af06df08162314f96a68d2a363e21a8ca"
|
checksum = "f31141ce3fc3e300ae89b78c0dd67f9708061d1d2eda54b8209346fd6be9a92c"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"rustls-pki-types",
|
"rustls-pki-types",
|
||||||
]
|
]
|
||||||
@ -1414,15 +1429,6 @@ dependencies = [
|
|||||||
"windows-targets 0.52.6",
|
"windows-targets 0.52.6",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "windows-sys"
|
|
||||||
version = "0.60.2"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "f2f500e4d28234f72040990ec9d39e3a6b950f9f22d3dba18416c35882612bcb"
|
|
||||||
dependencies = [
|
|
||||||
"windows-targets 0.53.5",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "windows-sys"
|
name = "windows-sys"
|
||||||
version = "0.61.2"
|
version = "0.61.2"
|
||||||
@ -1456,30 +1462,13 @@ dependencies = [
|
|||||||
"windows_aarch64_gnullvm 0.52.6",
|
"windows_aarch64_gnullvm 0.52.6",
|
||||||
"windows_aarch64_msvc 0.52.6",
|
"windows_aarch64_msvc 0.52.6",
|
||||||
"windows_i686_gnu 0.52.6",
|
"windows_i686_gnu 0.52.6",
|
||||||
"windows_i686_gnullvm 0.52.6",
|
"windows_i686_gnullvm",
|
||||||
"windows_i686_msvc 0.52.6",
|
"windows_i686_msvc 0.52.6",
|
||||||
"windows_x86_64_gnu 0.52.6",
|
"windows_x86_64_gnu 0.52.6",
|
||||||
"windows_x86_64_gnullvm 0.52.6",
|
"windows_x86_64_gnullvm 0.52.6",
|
||||||
"windows_x86_64_msvc 0.52.6",
|
"windows_x86_64_msvc 0.52.6",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "windows-targets"
|
|
||||||
version = "0.53.5"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "4945f9f551b88e0d65f3db0bc25c33b8acea4d9e41163edf90dcd0b19f9069f3"
|
|
||||||
dependencies = [
|
|
||||||
"windows-link",
|
|
||||||
"windows_aarch64_gnullvm 0.53.1",
|
|
||||||
"windows_aarch64_msvc 0.53.1",
|
|
||||||
"windows_i686_gnu 0.53.1",
|
|
||||||
"windows_i686_gnullvm 0.53.1",
|
|
||||||
"windows_i686_msvc 0.53.1",
|
|
||||||
"windows_x86_64_gnu 0.53.1",
|
|
||||||
"windows_x86_64_gnullvm 0.53.1",
|
|
||||||
"windows_x86_64_msvc 0.53.1",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "windows_aarch64_gnullvm"
|
name = "windows_aarch64_gnullvm"
|
||||||
version = "0.42.2"
|
version = "0.42.2"
|
||||||
@ -1492,12 +1481,6 @@ version = "0.52.6"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3"
|
checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3"
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "windows_aarch64_gnullvm"
|
|
||||||
version = "0.53.1"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "a9d8416fa8b42f5c947f8482c43e7d89e73a173cead56d044f6a56104a6d1b53"
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "windows_aarch64_msvc"
|
name = "windows_aarch64_msvc"
|
||||||
version = "0.42.2"
|
version = "0.42.2"
|
||||||
@ -1510,12 +1493,6 @@ version = "0.52.6"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469"
|
checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469"
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "windows_aarch64_msvc"
|
|
||||||
version = "0.53.1"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "b9d782e804c2f632e395708e99a94275910eb9100b2114651e04744e9b125006"
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "windows_i686_gnu"
|
name = "windows_i686_gnu"
|
||||||
version = "0.42.2"
|
version = "0.42.2"
|
||||||
@ -1528,24 +1505,12 @@ version = "0.52.6"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "8e9b5ad5ab802e97eb8e295ac6720e509ee4c243f69d781394014ebfe8bbfa0b"
|
checksum = "8e9b5ad5ab802e97eb8e295ac6720e509ee4c243f69d781394014ebfe8bbfa0b"
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "windows_i686_gnu"
|
|
||||||
version = "0.53.1"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "960e6da069d81e09becb0ca57a65220ddff016ff2d6af6a223cf372a506593a3"
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "windows_i686_gnullvm"
|
name = "windows_i686_gnullvm"
|
||||||
version = "0.52.6"
|
version = "0.52.6"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66"
|
checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66"
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "windows_i686_gnullvm"
|
|
||||||
version = "0.53.1"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "fa7359d10048f68ab8b09fa71c3daccfb0e9b559aed648a8f95469c27057180c"
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "windows_i686_msvc"
|
name = "windows_i686_msvc"
|
||||||
version = "0.42.2"
|
version = "0.42.2"
|
||||||
@ -1558,12 +1523,6 @@ version = "0.52.6"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66"
|
checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66"
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "windows_i686_msvc"
|
|
||||||
version = "0.53.1"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "1e7ac75179f18232fe9c285163565a57ef8d3c89254a30685b57d83a38d326c2"
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "windows_x86_64_gnu"
|
name = "windows_x86_64_gnu"
|
||||||
version = "0.42.2"
|
version = "0.42.2"
|
||||||
@ -1576,12 +1535,6 @@ version = "0.52.6"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78"
|
checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78"
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "windows_x86_64_gnu"
|
|
||||||
version = "0.53.1"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "9c3842cdd74a865a8066ab39c8a7a473c0778a3f29370b5fd6b4b9aa7df4a499"
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "windows_x86_64_gnullvm"
|
name = "windows_x86_64_gnullvm"
|
||||||
version = "0.42.2"
|
version = "0.42.2"
|
||||||
@ -1594,12 +1547,6 @@ version = "0.52.6"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d"
|
checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d"
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "windows_x86_64_gnullvm"
|
|
||||||
version = "0.53.1"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "0ffa179e2d07eee8ad8f57493436566c7cc30ac536a3379fdf008f47f6bb7ae1"
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "windows_x86_64_msvc"
|
name = "windows_x86_64_msvc"
|
||||||
version = "0.42.2"
|
version = "0.42.2"
|
||||||
@ -1612,32 +1559,26 @@ version = "0.52.6"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec"
|
checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec"
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "windows_x86_64_msvc"
|
|
||||||
version = "0.53.1"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "d6bbff5f0aada427a1e5a6da5f1f98158182f26556f345ac9e04d36d0ebed650"
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "winnow"
|
name = "winnow"
|
||||||
version = "0.7.14"
|
version = "1.0.1"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "5a5364e9d77fcdeeaa6062ced926ee3381faa2ee02d3eb83a5c27a8825540829"
|
checksum = "09dac053f1cd375980747450bfc7250c264eaae0583872e845c0c7cd578872b5"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"memchr",
|
"memchr",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "writeable"
|
name = "writeable"
|
||||||
version = "0.6.2"
|
version = "0.6.3"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "9edde0db4769d2dc68579893f2306b26c6ecfbe0ef499b013d731b7b9247e0b9"
|
checksum = "1ffae5123b2d3fc086436f8834ae3ab053a283cfac8fe0a0b8eaae044768a4c4"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "yoke"
|
name = "yoke"
|
||||||
version = "0.8.1"
|
version = "0.8.2"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "72d6e5c6afb84d73944e5cedb052c4680d5657337201555f9f2a16b7406d4954"
|
checksum = "abe8c5fda708d9ca3df187cae8bfb9ceda00dd96231bed36e445a1a48e66f9ca"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"stable_deref_trait",
|
"stable_deref_trait",
|
||||||
"yoke-derive",
|
"yoke-derive",
|
||||||
@ -1646,9 +1587,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "yoke-derive"
|
name = "yoke-derive"
|
||||||
version = "0.8.1"
|
version = "0.8.2"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "b659052874eb698efe5b9e8cf382204678a0086ebf46982b79d6ca3182927e5d"
|
checksum = "de844c262c8848816172cef550288e7dc6c7b7814b4ee56b3e1553f275f1858e"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"quote",
|
"quote",
|
||||||
@ -1658,18 +1599,18 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "zerofrom"
|
name = "zerofrom"
|
||||||
version = "0.1.6"
|
version = "0.1.7"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "50cc42e0333e05660c3587f3bf9d0478688e15d870fab3346451ce7f8c9fbea5"
|
checksum = "69faa1f2a1ea75661980b013019ed6687ed0e83d069bc1114e2cc74c6c04c4df"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"zerofrom-derive",
|
"zerofrom-derive",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "zerofrom-derive"
|
name = "zerofrom-derive"
|
||||||
version = "0.1.6"
|
version = "0.1.7"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "d71e5d6e06ab090c67b5e44993ec16b72dcbaabc526db883a360057678b48502"
|
checksum = "11532158c46691caf0f2593ea8358fed6bbf68a0315e80aae9bd41fbade684a1"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"quote",
|
"quote",
|
||||||
@ -1685,9 +1626,9 @@ checksum = "b97154e67e32c85465826e8bcc1c59429aaaf107c1e4a9e53c8d8ccd5eff88d0"
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "zerotrie"
|
name = "zerotrie"
|
||||||
version = "0.2.3"
|
version = "0.2.4"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "2a59c17a5562d507e4b54960e8569ebee33bee890c70aa3fe7b97e85a9fd7851"
|
checksum = "0f9152d31db0792fa83f70fb2f83148effb5c1f5b8c7686c3459e361d9bc20bf"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"displaydoc",
|
"displaydoc",
|
||||||
"yoke",
|
"yoke",
|
||||||
@ -1696,9 +1637,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "zerovec"
|
name = "zerovec"
|
||||||
version = "0.11.5"
|
version = "0.11.6"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "6c28719294829477f525be0186d13efa9a3c602f7ec202ca9e353d310fb9a002"
|
checksum = "90f911cbc359ab6af17377d242225f4d75119aec87ea711a880987b18cd7b239"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"yoke",
|
"yoke",
|
||||||
"zerofrom",
|
"zerofrom",
|
||||||
@ -1707,9 +1648,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "zerovec-derive"
|
name = "zerovec-derive"
|
||||||
version = "0.11.2"
|
version = "0.11.3"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "eadce39539ca5cb3985590102671f2567e659fca9666581ad3411d59207951f3"
|
checksum = "625dc425cab0dca6dc3c3319506e6593dcb08a9f387ea3b284dbd52a92c40555"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"quote",
|
"quote",
|
||||||
|
|||||||
@ -1,19 +1,25 @@
|
|||||||
[versions]
|
[versions]
|
||||||
slf4j = "2.0.17"
|
slf4j = "2.0.17"
|
||||||
junit = "6.0.2"
|
junit = "6.0.3"
|
||||||
|
micronaut-json-schema = "2.0.0-M8"
|
||||||
|
micronaut-core = "4.9.3"
|
||||||
|
|
||||||
[libraries]
|
[libraries]
|
||||||
bouncycastle = "org.bouncycastle:bcprov-jdk18on:1.83"
|
bouncycastle = "org.bouncycastle:bcprov-jdk18on:1.84"
|
||||||
jackson-databind = "com.fasterxml.jackson.core:jackson-databind:2.20.2"
|
jackson-databind = "com.fasterxml.jackson.core:jackson-databind:2.20.2"
|
||||||
argparse4j = "net.sourceforge.argparse4j:argparse4j:0.9.0"
|
argparse4j = "net.sourceforge.argparse4j:argparse4j:0.9.0"
|
||||||
dbusjava = "com.github.hypfvieh:dbus-java-transport-native-unixsocket:5.0.0"
|
dbusjava = "com.github.hypfvieh:dbus-java-transport-native-unixsocket:5.0.0"
|
||||||
zxing = "com.google.zxing:core:3.5.4"
|
zxing = "com.google.zxing:core:3.5.4"
|
||||||
|
micronaut-json-schema-annotations = { module = "io.micronaut.jsonschema:micronaut-json-schema-annotations", version.ref = "micronaut-json-schema" }
|
||||||
|
micronaut-json-schema-processor = { module = "io.micronaut.jsonschema:micronaut-json-schema-processor", version.ref = "micronaut-json-schema" }
|
||||||
|
micronaut-json-schema-generator = { module = "io.micronaut.jsonschema:micronaut-json-schema-generator", version.ref = "micronaut-json-schema" }
|
||||||
|
micronaut-inject-java = { module = "io.micronaut:micronaut-inject-java", version.ref = "micronaut-core" }
|
||||||
slf4j-api = { module = "org.slf4j:slf4j-api", version.ref = "slf4j" }
|
slf4j-api = { module = "org.slf4j:slf4j-api", version.ref = "slf4j" }
|
||||||
slf4j-jul = { module = "org.slf4j:jul-to-slf4j", version.ref = "slf4j" }
|
slf4j-jul = { module = "org.slf4j:jul-to-slf4j", version.ref = "slf4j" }
|
||||||
logback = "ch.qos.logback:logback-classic:1.5.32"
|
logback = "ch.qos.logback:logback-classic:1.5.32"
|
||||||
|
|
||||||
signalservice = "com.github.turasa:signal-service-java:2.15.3_unofficial_143"
|
signalservice = "com.github.turasa:signal-service-java:2.15.3_unofficial_144"
|
||||||
sqlite = "org.xerial:sqlite-jdbc:3.51.2.0"
|
sqlite = "org.xerial:sqlite-jdbc:3.53.0.0"
|
||||||
hikari = "com.zaxxer:HikariCP:7.0.2"
|
hikari = "com.zaxxer:HikariCP:7.0.2"
|
||||||
junit-jupiter-bom = { module = "org.junit:junit-bom", version.ref = "junit" }
|
junit-jupiter-bom = { module = "org.junit:junit-bom", version.ref = "junit" }
|
||||||
junit-jupiter = { module = "org.junit.jupiter:junit-jupiter", version.ref = "junit" }
|
junit-jupiter = { module = "org.junit.jupiter:junit-jupiter", version.ref = "junit" }
|
||||||
|
|||||||
@ -407,6 +407,10 @@ public interface Manager extends Closeable {
|
|||||||
|
|
||||||
void addClosedListener(Runnable listener);
|
void addClosedListener(Runnable listener);
|
||||||
|
|
||||||
|
void addUnidentifiedKeepAlive(String token);
|
||||||
|
|
||||||
|
void removeUnidentifiedKeepAlive(String token);
|
||||||
|
|
||||||
InputStream retrieveAttachment(final String id) throws IOException;
|
InputStream retrieveAttachment(final String id) throws IOException;
|
||||||
|
|
||||||
InputStream retrieveContactAvatar(final RecipientIdentifier.Single recipient) throws IOException, UnregisteredRecipientException;
|
InputStream retrieveContactAvatar(final RecipientIdentifier.Single recipient) throws IOException, UnregisteredRecipientException;
|
||||||
|
|||||||
@ -2,11 +2,11 @@ package org.asamk.signal.manager.api;
|
|||||||
|
|
||||||
public class CaptchaRequiredException extends Exception {
|
public class CaptchaRequiredException extends Exception {
|
||||||
|
|
||||||
private long nextAttemptTimestamp;
|
private long nextVerificationAttemptMilliseconds;
|
||||||
|
|
||||||
public CaptchaRequiredException(final long nextAttemptTimestamp) {
|
public CaptchaRequiredException(final long nextVerificationAttemptMilliseconds) {
|
||||||
super("Captcha required");
|
super("Captcha required");
|
||||||
this.nextAttemptTimestamp = nextAttemptTimestamp;
|
this.nextVerificationAttemptMilliseconds = nextVerificationAttemptMilliseconds;
|
||||||
}
|
}
|
||||||
|
|
||||||
public CaptchaRequiredException(final String message) {
|
public CaptchaRequiredException(final String message) {
|
||||||
@ -17,7 +17,7 @@ public class CaptchaRequiredException extends Exception {
|
|||||||
super(message, cause);
|
super(message, cause);
|
||||||
}
|
}
|
||||||
|
|
||||||
public long getNextAttemptTimestamp() {
|
public long getNextVerificationAttemptMilliseconds() {
|
||||||
return nextAttemptTimestamp;
|
return nextVerificationAttemptMilliseconds;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -10,12 +10,19 @@ public class ProofRequiredException extends Exception {
|
|||||||
|
|
||||||
private final String token;
|
private final String token;
|
||||||
private final Set<Option> options;
|
private final Set<Option> options;
|
||||||
private final long retryAfterSeconds;
|
private final long retryAfterMilliseconds;
|
||||||
|
|
||||||
public ProofRequiredException(org.whispersystems.signalservice.api.push.exceptions.ProofRequiredException e) {
|
public ProofRequiredException(final String token, final Set<Option> options, final long retryAfterMilliseconds) {
|
||||||
this.token = e.getToken();
|
super("Rate limit");
|
||||||
this.options = e.getOptions().stream().map(Option::from).collect(Collectors.toSet());
|
this.token = token;
|
||||||
this.retryAfterSeconds = e.getRetryAfterSeconds();
|
this.options = options;
|
||||||
|
this.retryAfterMilliseconds = retryAfterMilliseconds;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static ProofRequiredException from(org.whispersystems.signalservice.api.push.exceptions.ProofRequiredException e) {
|
||||||
|
return new ProofRequiredException(e.getToken(),
|
||||||
|
e.getOptions().stream().map(Option::from).collect(Collectors.toSet()),
|
||||||
|
e.getRetryAfterSeconds() * 1000L);
|
||||||
}
|
}
|
||||||
|
|
||||||
public String getToken() {
|
public String getToken() {
|
||||||
@ -26,8 +33,8 @@ public class ProofRequiredException extends Exception {
|
|||||||
return options;
|
return options;
|
||||||
}
|
}
|
||||||
|
|
||||||
public long getRetryAfterSeconds() {
|
public long getRetryAfterMilliseconds() {
|
||||||
return retryAfterSeconds;
|
return retryAfterMilliseconds;
|
||||||
}
|
}
|
||||||
|
|
||||||
public enum Option {
|
public enum Option {
|
||||||
|
|||||||
@ -2,14 +2,18 @@ package org.asamk.signal.manager.api;
|
|||||||
|
|
||||||
public class RateLimitException extends Exception {
|
public class RateLimitException extends Exception {
|
||||||
|
|
||||||
private final long nextAttemptTimestamp;
|
private final Long retryAfterMilliseconds;
|
||||||
|
|
||||||
public RateLimitException(final long nextAttemptTimestamp) {
|
public RateLimitException(final Long retryAfterMilliseconds) {
|
||||||
super("Rate limit");
|
super("Rate limit");
|
||||||
this.nextAttemptTimestamp = nextAttemptTimestamp;
|
this.retryAfterMilliseconds = retryAfterMilliseconds;
|
||||||
}
|
}
|
||||||
|
|
||||||
public long getNextAttemptTimestamp() {
|
public static RateLimitException from(org.whispersystems.signalservice.api.push.exceptions.RateLimitException e) {
|
||||||
return nextAttemptTimestamp;
|
return new RateLimitException(e.getRetryAfterMilliseconds().orElse(null));
|
||||||
|
}
|
||||||
|
|
||||||
|
public Long getRetryAfterMilliseconds() {
|
||||||
|
return retryAfterMilliseconds;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -9,13 +9,13 @@ public record SendMessageResult(
|
|||||||
boolean isNetworkFailure,
|
boolean isNetworkFailure,
|
||||||
boolean isUnregisteredFailure,
|
boolean isUnregisteredFailure,
|
||||||
boolean isIdentityFailure,
|
boolean isIdentityFailure,
|
||||||
boolean isRateLimitFailure,
|
RateLimitException rateLimitException,
|
||||||
ProofRequiredException proofRequiredFailure,
|
ProofRequiredException proofRequiredFailure,
|
||||||
boolean isInvalidPreKeyFailure
|
boolean isInvalidPreKeyFailure
|
||||||
) {
|
) {
|
||||||
|
|
||||||
public static SendMessageResult unregisteredFailure(RecipientAddress address) {
|
public static SendMessageResult unregisteredFailure(RecipientAddress address) {
|
||||||
return new SendMessageResult(address, false, false, true, false, false, null, false);
|
return new SendMessageResult(address, false, false, true, false, null, null, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static SendMessageResult from(
|
public static SendMessageResult from(
|
||||||
@ -23,16 +23,30 @@ public record SendMessageResult(
|
|||||||
RecipientResolver recipientResolver,
|
RecipientResolver recipientResolver,
|
||||||
RecipientAddressResolver addressResolver
|
RecipientAddressResolver addressResolver
|
||||||
) {
|
) {
|
||||||
|
final var rateLimitFailure = sendMessageResult.getRateLimitFailure();
|
||||||
|
final var proofRequiredFailure = sendMessageResult.getProofRequiredFailure();
|
||||||
return new SendMessageResult(addressResolver.resolveRecipientAddress(recipientResolver.resolveRecipient(
|
return new SendMessageResult(addressResolver.resolveRecipientAddress(recipientResolver.resolveRecipient(
|
||||||
sendMessageResult.getAddress())).toApiRecipientAddress(),
|
sendMessageResult.getAddress())).toApiRecipientAddress(),
|
||||||
sendMessageResult.isSuccess(),
|
sendMessageResult.isSuccess(),
|
||||||
sendMessageResult.isNetworkFailure(),
|
sendMessageResult.isNetworkFailure(),
|
||||||
sendMessageResult.isUnregisteredFailure(),
|
sendMessageResult.isUnregisteredFailure(),
|
||||||
sendMessageResult.getIdentityFailure() != null,
|
sendMessageResult.getIdentityFailure() != null,
|
||||||
sendMessageResult.getRateLimitFailure() != null || sendMessageResult.getProofRequiredFailure() != null,
|
rateLimitFailure == null ? null : RateLimitException.from(rateLimitFailure),
|
||||||
sendMessageResult.getProofRequiredFailure() == null
|
proofRequiredFailure == null ? null : ProofRequiredException.from(proofRequiredFailure),
|
||||||
? null
|
|
||||||
: new ProofRequiredException(sendMessageResult.getProofRequiredFailure()),
|
|
||||||
sendMessageResult.isInvalidPreKeyFailure());
|
sendMessageResult.isInvalidPreKeyFailure());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public boolean isRateLimitFailure() {
|
||||||
|
return this.rateLimitException != null || this.proofRequiredFailure != null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Long rateLimitRetryAfterMilliseconds() {
|
||||||
|
if (proofRequiredFailure != null) {
|
||||||
|
return proofRequiredFailure.getRetryAfterMilliseconds();
|
||||||
|
} else if (rateLimitException != null) {
|
||||||
|
return rateLimitException.getRetryAfterMilliseconds();
|
||||||
|
} else {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -2,6 +2,7 @@ package org.asamk.signal.manager.api;
|
|||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
import java.util.Objects;
|
||||||
|
|
||||||
public record SendMessageResults(long timestamp, Map<RecipientIdentifier, List<SendMessageResult>> results) {
|
public record SendMessageResults(long timestamp, Map<RecipientIdentifier, List<SendMessageResult>> results) {
|
||||||
|
|
||||||
@ -26,4 +27,18 @@ public record SendMessageResults(long timestamp, Map<RecipientIdentifier, List<S
|
|||||||
.flatMap(res -> res.stream().map(SendMessageResult::isRateLimitFailure))
|
.flatMap(res -> res.stream().map(SendMessageResult::isRateLimitFailure))
|
||||||
.allMatch(r -> r) && results.values().stream().mapToInt(List::size).sum() > 0;
|
.allMatch(r -> r) && results.values().stream().mapToInt(List::size).sum() > 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Longest rate-limit retry-after window across all rate-limited recipients, in milliseconds.
|
||||||
|
* Null when no recipient reported one (server omitted Retry-After, or no rate-limit failures).
|
||||||
|
*/
|
||||||
|
public Long maxRateLimitRetryAfterMilliseconds() {
|
||||||
|
return results.values()
|
||||||
|
.stream()
|
||||||
|
.flatMap(List::stream)
|
||||||
|
.map(SendMessageResult::rateLimitRetryAfterMilliseconds)
|
||||||
|
.filter(Objects::nonNull)
|
||||||
|
.max(Long::compareTo)
|
||||||
|
.orElse(null);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -105,6 +105,8 @@ public class CallManager implements AutoCloseable {
|
|||||||
recipientAddress,
|
recipientAddress,
|
||||||
recipientId);
|
recipientId);
|
||||||
activeCalls.put(callId, state);
|
activeCalls.put(callId, state);
|
||||||
|
dependencies.getAuthenticatedSignalWebSocket().registerKeepAliveToken("call" + callId);
|
||||||
|
dependencies.getUnauthenticatedSignalWebSocket().registerKeepAliveToken("call" + callId);
|
||||||
fireCallEvent(state, null);
|
fireCallEvent(state, null);
|
||||||
|
|
||||||
// Spawn call tunnel binary and connect control channel
|
// Spawn call tunnel binary and connect control channel
|
||||||
@ -197,11 +199,6 @@ public class CallManager implements AutoCloseable {
|
|||||||
if (callEventListeners.isEmpty()) {
|
if (callEventListeners.isEmpty()) {
|
||||||
logger.debug("Ignoring incoming offer for call {}: no call event listeners registered",
|
logger.debug("Ignoring incoming offer for call {}: no call event listeners registered",
|
||||||
callIdUnsigned(callId));
|
callIdUnsigned(callId));
|
||||||
|
|
||||||
final var result = sendBusyMessage(callId, recipientId, deviceId);
|
|
||||||
if (!result.isSuccess()) {
|
|
||||||
logger.warn("Failed to send busy for unhandled call {}", callIdUnsigned(callId));
|
|
||||||
}
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -701,6 +698,8 @@ public class CallManager implements AutoCloseable {
|
|||||||
|
|
||||||
private void endCall(final long callId, final String reason) {
|
private void endCall(final long callId, final String reason) {
|
||||||
var state = activeCalls.remove(callId);
|
var state = activeCalls.remove(callId);
|
||||||
|
dependencies.getAuthenticatedSignalWebSocket().removeKeepAliveToken("call" + callId);
|
||||||
|
dependencies.getUnauthenticatedSignalWebSocket().removeKeepAliveToken("call" + callId);
|
||||||
if (state == null) return;
|
if (state == null) return;
|
||||||
|
|
||||||
state.state = CallInfo.State.ENDED;
|
state.state = CallInfo.State.ENDED;
|
||||||
|
|||||||
@ -134,7 +134,9 @@ public final class ProfileHelper {
|
|||||||
SignalServiceProfile.RequestType.PROFILE_AND_CREDENTIAL,
|
SignalServiceProfile.RequestType.PROFILE_AND_CREDENTIAL,
|
||||||
false));
|
false));
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
logger.warn("Failed to retrieve profile key credential, ignoring: {}", e.getMessage());
|
logger.warn("Failed to retrieve profile key credential for {}, ignoring: {}",
|
||||||
|
context.getRecipientHelper().resolveSignalServiceAddress(recipientId).getIdentifier(),
|
||||||
|
e.getMessage());
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -263,7 +265,9 @@ public final class ProfileHelper {
|
|||||||
try {
|
try {
|
||||||
blockingGetProfile(retrieveProfile(recipientId, SignalServiceProfile.RequestType.PROFILE, false));
|
blockingGetProfile(retrieveProfile(recipientId, SignalServiceProfile.RequestType.PROFILE, false));
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
logger.warn("Failed to retrieve profile, ignoring: {}", e.getMessage());
|
logger.warn("Failed to retrieve profile for {}, ignoring: {}",
|
||||||
|
context.getRecipientHelper().resolveSignalServiceAddress(recipientId).getIdentifier(),
|
||||||
|
e.getMessage());
|
||||||
}
|
}
|
||||||
|
|
||||||
return account.getProfileStore().getProfile(recipientId);
|
return account.getProfileStore().getProfile(recipientId);
|
||||||
@ -381,7 +385,9 @@ public final class ProfileHelper {
|
|||||||
|
|
||||||
logger.trace("Done handling retrieved profile");
|
logger.trace("Done handling retrieved profile");
|
||||||
}).doOnError(e -> {
|
}).doOnError(e -> {
|
||||||
logger.warn("Failed to retrieve profile, ignoring: {}", e.getMessage());
|
logger.warn("Failed to retrieve profile for {}, ignoring: {}",
|
||||||
|
context.getRecipientHelper().resolveSignalServiceAddress(recipientId).getIdentifier(),
|
||||||
|
e.getMessage());
|
||||||
final var profile = account.getProfileStore().getProfile(recipientId);
|
final var profile = account.getProfileStore().getProfile(recipientId);
|
||||||
final var newProfile = (
|
final var newProfile = (
|
||||||
profile == null ? Profile.newBuilder() : Profile.newBuilder(profile)
|
profile == null ? Profile.newBuilder() : Profile.newBuilder(profile)
|
||||||
|
|||||||
@ -102,9 +102,6 @@ public class ReceiveHelper {
|
|||||||
signalWebSocket.connect();
|
signalWebSocket.connect();
|
||||||
signalWebSocket.registerKeepAliveToken("receive");
|
signalWebSocket.registerKeepAliveToken("receive");
|
||||||
|
|
||||||
final var unauthenticatedSignalWebSocket = dependencies.getUnauthenticatedSignalWebSocket();
|
|
||||||
unauthenticatedSignalWebSocket.registerKeepAliveToken("receive");
|
|
||||||
|
|
||||||
try {
|
try {
|
||||||
receiveMessagesInternal(signalWebSocket, timeout, maxMessages, handler, queuedActions);
|
receiveMessagesInternal(signalWebSocket, timeout, maxMessages, handler, queuedActions);
|
||||||
} finally {
|
} finally {
|
||||||
@ -113,7 +110,6 @@ public class ReceiveHelper {
|
|||||||
queuedActions.clear();
|
queuedActions.clear();
|
||||||
signalWebSocket.removeKeepAliveToken("receive");
|
signalWebSocket.removeKeepAliveToken("receive");
|
||||||
signalWebSocket.disconnect();
|
signalWebSocket.disconnect();
|
||||||
unauthenticatedSignalWebSocket.removeKeepAliveToken("receive");
|
|
||||||
webSocketStateDisposable.dispose();
|
webSocketStateDisposable.dispose();
|
||||||
shouldStop = false;
|
shouldStop = false;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -278,7 +278,7 @@ public class ManagerImpl implements Manager {
|
|||||||
registeredUsers = context.getRecipientHelper().getRegisteredUsers(canonicalizedNumbersSet);
|
registeredUsers = context.getRecipientHelper().getRegisteredUsers(canonicalizedNumbersSet);
|
||||||
} catch (CdsiResourceExhaustedException e) {
|
} catch (CdsiResourceExhaustedException e) {
|
||||||
logger.debug("CDSI resource exhausted: {}", e.getMessage());
|
logger.debug("CDSI resource exhausted: {}", e.getMessage());
|
||||||
throw new RateLimitException(System.currentTimeMillis() + e.getRetryAfterSeconds() * 1000L);
|
throw new RateLimitException(e.getRetryAfterSeconds() * 1000L);
|
||||||
}
|
}
|
||||||
|
|
||||||
return numbers.stream().collect(Collectors.toMap(n -> n, n -> {
|
return numbers.stream().collect(Collectors.toMap(n -> n, n -> {
|
||||||
@ -1712,6 +1712,16 @@ public class ManagerImpl implements Manager {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void addUnidentifiedKeepAlive(final String token) {
|
||||||
|
dependencies.getUnauthenticatedSignalWebSocket().registerKeepAliveToken(token);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void removeUnidentifiedKeepAlive(final String token) {
|
||||||
|
dependencies.getUnauthenticatedSignalWebSocket().removeKeepAliveToken(token);
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void addCallEventListener(final CallEventListener listener) {
|
public void addCallEventListener(final CallEventListener listener) {
|
||||||
context.getCallManager().addCallEventListener(listener);
|
context.getCallManager().addCallEventListener(listener);
|
||||||
|
|||||||
@ -301,7 +301,7 @@ public class SignalDependencies {
|
|||||||
getLibSignalNetwork(),
|
getLibSignalNetwork(),
|
||||||
credentialsProvider,
|
credentialsProvider,
|
||||||
allowStories,
|
allowStories,
|
||||||
healthMonitor), () -> true, timer, TimeUnit.SECONDS.toMillis(10));
|
healthMonitor), () -> true, timer, TimeUnit.SECONDS.toMillis(30));
|
||||||
healthMonitor.monitor(authenticatedSignalWebSocket);
|
healthMonitor.monitor(authenticatedSignalWebSocket);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@ -316,7 +316,7 @@ public class SignalDependencies {
|
|||||||
getLibSignalNetwork(),
|
getLibSignalNetwork(),
|
||||||
null,
|
null,
|
||||||
allowStories,
|
allowStories,
|
||||||
healthMonitor), () -> true, timer, TimeUnit.SECONDS.toMillis(10));
|
healthMonitor), () -> true, timer, TimeUnit.SECONDS.toMillis(30));
|
||||||
healthMonitor.monitor(unauthenticatedSignalWebSocket);
|
healthMonitor.monitor(unauthenticatedSignalWebSocket);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|||||||
@ -204,7 +204,7 @@ public class SenderKeySharedStore {
|
|||||||
).formatted(TABLE_SENDER_KEY_SHARED);
|
).formatted(TABLE_SENDER_KEY_SHARED);
|
||||||
try (final var statement = connection.prepareStatement(sql)) {
|
try (final var statement = connection.prepareStatement(sql)) {
|
||||||
for (final var entry : newEntries) {
|
for (final var entry : newEntries) {
|
||||||
statement.setString(1, entry.toString());
|
statement.setString(1, entry.address());
|
||||||
statement.setInt(2, entry.deviceId());
|
statement.setInt(2, entry.deviceId());
|
||||||
statement.setBytes(3, UuidUtil.toByteArray(distributionId.asUuid()));
|
statement.setBytes(3, UuidUtil.toByteArray(distributionId.asUuid()));
|
||||||
statement.setLong(4, System.currentTimeMillis());
|
statement.setLong(4, System.currentTimeMillis());
|
||||||
|
|||||||
@ -65,14 +65,12 @@ public class NumberVerificationUtils {
|
|||||||
if (nextAttempt == null) {
|
if (nextAttempt == null) {
|
||||||
throw new VerificationMethodNotAvailableException();
|
throw new VerificationMethodNotAvailableException();
|
||||||
} else if (nextAttempt > 0) {
|
} else if (nextAttempt > 0) {
|
||||||
final var timestamp = sessionResponse.getClientReceivedAtMilliseconds() + nextAttempt * 1000;
|
throw new RateLimitException(nextAttempt * 1000L);
|
||||||
throw new RateLimitException(timestamp);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
final var nextVerificationAttempt = sessionResponse.getMetadata().getNextVerificationAttempt();
|
final var nextVerificationAttempt = sessionResponse.getMetadata().getNextVerificationAttempt();
|
||||||
if (nextVerificationAttempt != null && nextVerificationAttempt > 0) {
|
if (nextVerificationAttempt != null && nextVerificationAttempt > 0) {
|
||||||
final var timestamp = sessionResponse.getClientReceivedAtMilliseconds() + nextVerificationAttempt * 1000;
|
throw new CaptchaRequiredException(nextVerificationAttempt * 1000L);
|
||||||
throw new CaptchaRequiredException(timestamp);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (sessionResponse.getMetadata().getRequestedInformation().contains("captcha")) {
|
if (sessionResponse.getMetadata().getRequestedInformation().contains("captcha")) {
|
||||||
|
|||||||
@ -14,8 +14,8 @@ all: $(MANPAGESRC)
|
|||||||
.PHONY: install
|
.PHONY: install
|
||||||
install: all
|
install: all
|
||||||
$(MKDIR) -p man1 man5
|
$(MKDIR) -p man1 man5
|
||||||
for f in *.1; do $(GZIP) < "$$f" > man1/"$$f".gz ; done
|
for f in *.1; do $(GZIP) -n < "$$f" > man1/"$$f".gz ; done
|
||||||
for f in *.5; do $(GZIP) < "$$f" > man5/"$$f".gz ; done
|
for f in *.5; do $(GZIP) -n < "$$f" > man5/"$$f".gz ; done
|
||||||
|
|
||||||
.PHONY: clean
|
.PHONY: clean
|
||||||
clean:
|
clean:
|
||||||
|
|||||||
@ -1168,6 +1168,7 @@ signal-cli -a ACCOUNT trust -a RECIPIENT
|
|||||||
* *3*: Server or IO error
|
* *3*: Server or IO error
|
||||||
* *4*: Sending failed due to untrusted key
|
* *4*: Sending failed due to untrusted key
|
||||||
* *5*: Server rate limiting error
|
* *5*: Server rate limiting error
|
||||||
|
* *6*: CAPTCHA was rejected
|
||||||
|
|
||||||
== Files
|
== Files
|
||||||
|
|
||||||
|
|||||||
34
reproducible-builds/README.md
Normal file
34
reproducible-builds/README.md
Normal file
@ -0,0 +1,34 @@
|
|||||||
|
# Reproducible builds
|
||||||
|
|
||||||
|
This process lets you verify that the version of signal-cli that was downloaded from the Github Releases matches the source code in the public repository.
|
||||||
|
|
||||||
|
This is achieved by replicating the build environment as Docker images.
|
||||||
|
|
||||||
|
Currently, only the following binaries are reproducible:
|
||||||
|
|
||||||
|
- [x] JAR package (`signal-cli-XXX.tar.gz`)
|
||||||
|
- [ ] Native binary (`signal-cli-XXX-Linux-native.tar.gz`)
|
||||||
|
- [x] Rust client binary (`signal-cli-XXX-Linux-client.tar.gz`)
|
||||||
|
|
||||||
|
In the following section, we will use signal-cli version 0.14.2 as the reference example. Simply replace all occurrences of 0.14.2 with the version number you are about to verify.
|
||||||
|
|
||||||
|
## Step-by-step instructions
|
||||||
|
|
||||||
|
### 0. Prerequisites
|
||||||
|
|
||||||
|
Before you begin, ensure you have the following installed:
|
||||||
|
|
||||||
|
- git
|
||||||
|
- docker (or podman)
|
||||||
|
|
||||||
|
### 1. Verifying reproducibility
|
||||||
|
|
||||||
|
```bash
|
||||||
|
git clone --depth 1 --branch v0.14.2 https://github.com/AsamK/signal-cli
|
||||||
|
cd ./signal-cli
|
||||||
|
./reproducible-builds/verify.sh
|
||||||
|
```
|
||||||
|
|
||||||
|
If each one ends with `... matches!` for every binary (except the native one for now), you're good to go! You've successfully verified that the Github Release binaries were built from exactly the same code as is in the signal-cli git repository.
|
||||||
|
|
||||||
|
If you get `... doesn't match!`, it means something went wrong (except for the native one for now). Please [open an issue](https://github.com/AsamK/signal-cli/issues/new/choose).
|
||||||
13
reproducible-builds/build.Containerfile
Normal file
13
reproducible-builds/build.Containerfile
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
ARG ZULU_TAG="25.0.2-jdk@sha256:9582df6c4415d9c770eb5ff8fce426ebba53631149c9eb083ee126568d32fab3"
|
||||||
|
|
||||||
|
FROM docker.io/azul/zulu-openjdk:$ZULU_TAG
|
||||||
|
ENV SOURCE_DATE_EPOCH=1767225600
|
||||||
|
ENV LANG=C.UTF-8
|
||||||
|
ENV LC_CTYPE=en_US.UTF-8
|
||||||
|
ARG SNAPSHOT=20260101T000000Z
|
||||||
|
RUN echo "deb http://snapshot.ubuntu.com/ubuntu/${SNAPSHOT}/ jammy main" > /etc/apt/sources.list \
|
||||||
|
&& echo "deb http://snapshot.ubuntu.com/ubuntu/${SNAPSHOT}/ jammy universe" >> /etc/apt/sources.list
|
||||||
|
RUN apt update && apt install -y make asciidoc-base
|
||||||
|
COPY --chmod=0700 reproducible-builds/entrypoint.sh /usr/local/bin/entrypoint.sh
|
||||||
|
WORKDIR /signal-cli
|
||||||
|
ENTRYPOINT [ "/usr/local/bin/entrypoint.sh", "build" ]
|
||||||
50
reproducible-builds/build.sh
Executable file
50
reproducible-builds/build.sh
Executable file
@ -0,0 +1,50 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
set -eu
|
||||||
|
|
||||||
|
ROOT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)/../"
|
||||||
|
cd "$ROOT_DIR"
|
||||||
|
rm -rf "$ROOT_DIR/dist"
|
||||||
|
mkdir -p "$ROOT_DIR/dist"
|
||||||
|
|
||||||
|
if command -v podman >/dev/null; then
|
||||||
|
ENGINE=podman
|
||||||
|
USER=
|
||||||
|
else
|
||||||
|
ENGINE=docker
|
||||||
|
USER="--user $(id -u):$(id -g)"
|
||||||
|
fi
|
||||||
|
|
||||||
|
VERSION=$(sed -n 's/\s*version\s*=\s*"\(.*\)".*/\1/p' build.gradle.kts | tail -n1)
|
||||||
|
echo "$VERSION" >dist/VERSION
|
||||||
|
|
||||||
|
$ENGINE build -t signal-cli:build ${OVERRIDE_JAVA_VERSION:+--build-arg ZULU_TAG=$OVERRIDE_JAVA_VERSION} -f reproducible-builds/build.Containerfile .
|
||||||
|
$ENGINE build -t signal-cli:native -f reproducible-builds/native.Containerfile .
|
||||||
|
$ENGINE build -t signal-cli:client -f reproducible-builds/client.Containerfile .
|
||||||
|
|
||||||
|
# Build jar
|
||||||
|
git clean -Xfd -e '!/dist/' -e '!/dist/**' -e '!/github/' -e '!/github/**'
|
||||||
|
# shellcheck disable=SC2086
|
||||||
|
$ENGINE run --pull=never --rm -v "$(pwd)":/signal-cli:Z -e VERSION="$VERSION" $USER signal-cli:build
|
||||||
|
mv build/distributions/signal-cli-*.tar.gz dist/
|
||||||
|
|
||||||
|
if [ -n "${OVERRIDE_JAVA_VERSION:-}" ]; then
|
||||||
|
echo -e "\e[33mBuild was performed with overridden Java version $OVERRIDE_JAVA_VERSION, native-image and client will not be built.\e[0m"
|
||||||
|
exit 0
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Build native-image
|
||||||
|
git clean -Xfd -e '!/dist/' -e '!/dist/**' -e '!/github/' -e '!/github/**'
|
||||||
|
# shellcheck disable=SC2086
|
||||||
|
$ENGINE run --pull=never --rm -v "$(pwd)":/signal-cli:Z -e VERSION="$VERSION" $USER signal-cli:native
|
||||||
|
mv build/signal-cli-*-Linux-native.tar.gz dist/
|
||||||
|
|
||||||
|
# Build rust client
|
||||||
|
git clean -Xfd -e '!/dist/' -e '!/dist/**' -e '!/github/' -e '!/github/**'
|
||||||
|
# shellcheck disable=SC2086
|
||||||
|
$ENGINE run --pull=never --rm -v "$(pwd)":/signal-cli:Z -e VERSION="$VERSION" $USER signal-cli:client
|
||||||
|
mv build/signal-cli-*-Linux-client.tar.gz dist/
|
||||||
|
|
||||||
|
ls -lsh dist/
|
||||||
|
|
||||||
|
echo -e "\e[32mBuild successful!\e[0m"
|
||||||
7
reproducible-builds/client.Containerfile
Normal file
7
reproducible-builds/client.Containerfile
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
FROM docker.io/rust:1.94.1-slim-trixie@sha256:c6a474d7164ea2455e09b60a759b1edca38db7373c5689c1dae31780de4e71ac
|
||||||
|
ENV SOURCE_DATE_EPOCH=1767225600
|
||||||
|
ENV LANG=C.UTF-8
|
||||||
|
ENV LC_CTYPE=en_US.UTF-8
|
||||||
|
COPY --chmod=0700 reproducible-builds/entrypoint.sh /usr/local/bin/entrypoint.sh
|
||||||
|
WORKDIR /signal-cli
|
||||||
|
ENTRYPOINT [ "/usr/local/bin/entrypoint.sh", "client" ]
|
||||||
78
reproducible-builds/entrypoint.sh
Normal file
78
reproducible-builds/entrypoint.sh
Normal file
@ -0,0 +1,78 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
set -eu
|
||||||
|
|
||||||
|
echo "Build '$1' variant $VERSION ..."
|
||||||
|
|
||||||
|
function reset_file_dates() {
|
||||||
|
find . -exec touch -m -d "@$SOURCE_DATE_EPOCH" {} \;
|
||||||
|
}
|
||||||
|
|
||||||
|
reset_file_dates
|
||||||
|
|
||||||
|
if [ "$1" == "build" ]; then
|
||||||
|
|
||||||
|
./gradlew build \
|
||||||
|
--no-daemon \
|
||||||
|
--max-workers=1 \
|
||||||
|
-Dkotlin.compiler.execution.strategy=in-process \
|
||||||
|
--no-build-cache \
|
||||||
|
-Dorg.gradle.caching=false \
|
||||||
|
-Porg.gradle.java.installations.auto-download=false \
|
||||||
|
-Porg.gradle.java.installations.auto-detect=false
|
||||||
|
cd man
|
||||||
|
make install
|
||||||
|
cd ..
|
||||||
|
tar_archive="build/distributions/signal-cli-${VERSION}.tar"
|
||||||
|
tar --transform="flags=r;s|man|signal-cli-${VERSION}/man|" -rf "$tar_archive" man/man{1,5}
|
||||||
|
|
||||||
|
# Remake the tarball to ensure reproducible file order and timestamps
|
||||||
|
mkdir -p build/extracted
|
||||||
|
tar -xf "$tar_archive" -C build/extracted/
|
||||||
|
reset_file_dates
|
||||||
|
rm -f "$tar_archive"
|
||||||
|
tar --sort=name --mtime="@$SOURCE_DATE_EPOCH" --transform='s|^\./||' --owner=0 --group=0 --numeric-owner -cf "$tar_archive" -C build/extracted .
|
||||||
|
|
||||||
|
gzip -n -9 "$tar_archive"
|
||||||
|
|
||||||
|
elif [ "$1" == "native" ]; then
|
||||||
|
|
||||||
|
./gradlew nativeCompile \
|
||||||
|
--no-daemon \
|
||||||
|
--max-workers=1 \
|
||||||
|
-Dkotlin.compiler.execution.strategy=in-process \
|
||||||
|
--no-build-cache \
|
||||||
|
-Dorg.gradle.caching=false \
|
||||||
|
-Dgraalvm.native-image.build-time=2026-01-01T00:00:00Z \
|
||||||
|
-Porg.gradle.java.installations.auto-download=false \
|
||||||
|
-Porg.gradle.java.installations.auto-detect=false
|
||||||
|
|
||||||
|
strip --strip-all \
|
||||||
|
--remove-section=.note.gnu.build-id \
|
||||||
|
--remove-section=.comment \
|
||||||
|
--remove-section=.gnu_debuglink \
|
||||||
|
--remove-section=.annobin.notes \
|
||||||
|
--remove-section=.gnu.build.attributes \
|
||||||
|
--remove-section=.note.ABI-tag \
|
||||||
|
build/native/nativeCompile/signal-cli
|
||||||
|
|
||||||
|
chmod +x build/native/nativeCompile/signal-cli
|
||||||
|
reset_file_dates
|
||||||
|
tar --sort=name --mtime="@$SOURCE_DATE_EPOCH" --owner=0 --group=0 --numeric-owner -cf "build/signal-cli-${VERSION}-Linux-native.tar" -C build/native/nativeCompile signal-cli
|
||||||
|
gzip -n -9 "build/signal-cli-${VERSION}-Linux-native.tar"
|
||||||
|
|
||||||
|
elif [ "$1" == "client" ]; then
|
||||||
|
|
||||||
|
cd client
|
||||||
|
cargo build --release --locked
|
||||||
|
cd ..
|
||||||
|
chmod +x client/target/release/signal-cli-client
|
||||||
|
mkdir -p build
|
||||||
|
reset_file_dates
|
||||||
|
tar --sort=name --mtime="@$SOURCE_DATE_EPOCH" --owner=0 --group=0 --numeric-owner -cf "build/signal-cli-${VERSION}-Linux-client.tar" -C client/target/release signal-cli-client
|
||||||
|
gzip -n -9 "build/signal-cli-${VERSION}-Linux-client.tar"
|
||||||
|
|
||||||
|
else
|
||||||
|
echo "Unknown build variant '$1'"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
7
reproducible-builds/native.Containerfile
Normal file
7
reproducible-builds/native.Containerfile
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
FROM container-registry.oracle.com/graalvm/native-image:25.0.2@sha256:4c0d5919f6840d89721274eb8cf81962faa2f870b816967e6732e2a151b150d8
|
||||||
|
ENV SOURCE_DATE_EPOCH=1767225600
|
||||||
|
ENV LANG=C.UTF-8
|
||||||
|
ENV LC_CTYPE=en_US.UTF-8
|
||||||
|
COPY --chmod=0700 reproducible-builds/entrypoint.sh /usr/local/bin/entrypoint.sh
|
||||||
|
WORKDIR /signal-cli
|
||||||
|
ENTRYPOINT [ "/usr/local/bin/entrypoint.sh", "native" ]
|
||||||
44
reproducible-builds/verify.sh
Executable file
44
reproducible-builds/verify.sh
Executable file
@ -0,0 +1,44 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
set -eu
|
||||||
|
|
||||||
|
ROOT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)/../"
|
||||||
|
cd "$ROOT_DIR"
|
||||||
|
rm -rf "$ROOT_DIR/github"
|
||||||
|
mkdir -p "$ROOT_DIR/github"
|
||||||
|
|
||||||
|
VERSION=$(sed -n 's/\s*version\s*=\s*"\(.*\)".*/\1/p' build.gradle.kts | tail -n1)
|
||||||
|
|
||||||
|
echo "Download latest release from GitHub..."
|
||||||
|
|
||||||
|
curl -L --fail "https://github.com/AsamK/signal-cli/releases/download/v${VERSION}/signal-cli-${VERSION}.tar.gz" -o "github/signal-cli-${VERSION}.tar.gz"
|
||||||
|
curl -L --fail "https://github.com/AsamK/signal-cli/releases/download/v${VERSION}/signal-cli-${VERSION}-Linux-native.tar.gz" -o "github/signal-cli-${VERSION}-Linux-native.tar.gz"
|
||||||
|
curl -L --fail "https://github.com/AsamK/signal-cli/releases/download/v${VERSION}/signal-cli-${VERSION}-Linux-client.tar.gz" -o "github/signal-cli-${VERSION}-Linux-client.tar.gz"
|
||||||
|
|
||||||
|
./reproducible-builds/build.sh
|
||||||
|
|
||||||
|
rm -f {github,dist}/VERSION
|
||||||
|
|
||||||
|
echo "commit: $(git rev-parse HEAD)"
|
||||||
|
|
||||||
|
echo "sha256 hashes of GitHub release:"
|
||||||
|
sha256sum github/*
|
||||||
|
echo "sha256 hashes of locally built files:"
|
||||||
|
sha256sum dist/*
|
||||||
|
|
||||||
|
reproducible=true
|
||||||
|
for file in $(cd github && find . -type f); do
|
||||||
|
if diff "github/$file" "dist/$file" >/dev/null 2>&1; then
|
||||||
|
echo -e "\e[32m[+] '$(basename "$file")' matches!\e[0m"
|
||||||
|
elif [[ "$file" =~ "native" ]]; then
|
||||||
|
echo -e "\e[33m[-] '$(basename "$file")' doesn't match! (not supported yet)\e[0m"
|
||||||
|
reproducible=false
|
||||||
|
else
|
||||||
|
echo -e "\e[31m[-] '$(basename "$file")' doesn't match!\e[0m"
|
||||||
|
reproducible=false
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
|
||||||
|
if [ "$reproducible" = false ]; then
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
@ -8,7 +8,7 @@ public class BaseConfig {
|
|||||||
public static final String PROJECT_VERSION = BaseConfig.class.getPackage().getImplementationVersion();
|
public static final String PROJECT_VERSION = BaseConfig.class.getPackage().getImplementationVersion();
|
||||||
|
|
||||||
static final String USER_AGENT_SIGNAL_ANDROID = Optional.ofNullable(System.getenv("SIGNAL_CLI_USER_AGENT"))
|
static final String USER_AGENT_SIGNAL_ANDROID = Optional.ofNullable(System.getenv("SIGNAL_CLI_USER_AGENT"))
|
||||||
.orElse("Signal-Android/8.6.1");
|
.orElse("Signal-Android/8.8.0");
|
||||||
static final String USER_AGENT_SIGNAL_CLI = PROJECT_NAME == null
|
static final String USER_AGENT_SIGNAL_CLI = PROJECT_NAME == null
|
||||||
? "signal-cli"
|
? "signal-cli"
|
||||||
: PROJECT_NAME + "/" + PROJECT_VERSION;
|
: PROJECT_NAME + "/" + PROJECT_VERSION;
|
||||||
|
|||||||
@ -22,6 +22,7 @@ import net.sourceforge.argparse4j.impl.Arguments;
|
|||||||
import net.sourceforge.argparse4j.inf.ArgumentParserException;
|
import net.sourceforge.argparse4j.inf.ArgumentParserException;
|
||||||
import net.sourceforge.argparse4j.inf.Namespace;
|
import net.sourceforge.argparse4j.inf.Namespace;
|
||||||
|
|
||||||
|
import org.asamk.signal.commands.exceptions.CaptchaRejectedErrorException;
|
||||||
import org.asamk.signal.commands.exceptions.CommandException;
|
import org.asamk.signal.commands.exceptions.CommandException;
|
||||||
import org.asamk.signal.commands.exceptions.IOErrorException;
|
import org.asamk.signal.commands.exceptions.IOErrorException;
|
||||||
import org.asamk.signal.commands.exceptions.RateLimitErrorException;
|
import org.asamk.signal.commands.exceptions.RateLimitErrorException;
|
||||||
@ -128,6 +129,7 @@ public class Main {
|
|||||||
case IOErrorException ioErrorException -> 3;
|
case IOErrorException ioErrorException -> 3;
|
||||||
case UntrustedKeyErrorException untrustedKeyErrorException -> 4;
|
case UntrustedKeyErrorException untrustedKeyErrorException -> 4;
|
||||||
case RateLimitErrorException rateLimitErrorException -> 5;
|
case RateLimitErrorException rateLimitErrorException -> 5;
|
||||||
|
case CaptchaRejectedErrorException captchaRejectedErrorException -> 6;
|
||||||
case null -> 2;
|
case null -> 2;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|||||||
@ -3,9 +3,9 @@ package org.asamk.signal.commands;
|
|||||||
import net.sourceforge.argparse4j.inf.Namespace;
|
import net.sourceforge.argparse4j.inf.Namespace;
|
||||||
import net.sourceforge.argparse4j.inf.Subparser;
|
import net.sourceforge.argparse4j.inf.Subparser;
|
||||||
|
|
||||||
|
import org.asamk.signal.commands.exceptions.CaptchaRejectedErrorException;
|
||||||
import org.asamk.signal.commands.exceptions.CommandException;
|
import org.asamk.signal.commands.exceptions.CommandException;
|
||||||
import org.asamk.signal.commands.exceptions.IOErrorException;
|
import org.asamk.signal.commands.exceptions.IOErrorException;
|
||||||
import org.asamk.signal.commands.exceptions.UserErrorException;
|
|
||||||
import org.asamk.signal.manager.Manager;
|
import org.asamk.signal.manager.Manager;
|
||||||
import org.asamk.signal.manager.api.CaptchaRejectedException;
|
import org.asamk.signal.manager.api.CaptchaRejectedException;
|
||||||
import org.asamk.signal.output.OutputWriter;
|
import org.asamk.signal.output.OutputWriter;
|
||||||
@ -41,8 +41,8 @@ public class SubmitRateLimitChallengeCommand implements JsonRpcLocalCommand {
|
|||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
throw new IOErrorException("Submit challenge error: " + e.getMessage(), e);
|
throw new IOErrorException("Submit challenge error: " + e.getMessage(), e);
|
||||||
} catch (CaptchaRejectedException e) {
|
} catch (CaptchaRejectedException e) {
|
||||||
throw new UserErrorException(
|
throw new CaptchaRejectedErrorException(
|
||||||
"Captcha rejected, it may be outdated, already used or solved from a different IP address.");
|
"Captcha rejected, it may be outdated, already used or solved from a different IP address.", e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -0,0 +1,10 @@
|
|||||||
|
package org.asamk.signal.commands.exceptions;
|
||||||
|
|
||||||
|
import org.asamk.signal.manager.api.CaptchaRejectedException;
|
||||||
|
|
||||||
|
public final class CaptchaRejectedErrorException extends CommandException {
|
||||||
|
|
||||||
|
public CaptchaRejectedErrorException(final String message, final CaptchaRejectedException cause) {
|
||||||
|
super(message, cause);
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -1,6 +1,6 @@
|
|||||||
package org.asamk.signal.commands.exceptions;
|
package org.asamk.signal.commands.exceptions;
|
||||||
|
|
||||||
public sealed abstract class CommandException extends Exception permits IOErrorException, RateLimitErrorException, UnexpectedErrorException, UntrustedKeyErrorException, UserErrorException {
|
public sealed abstract class CommandException extends Exception permits CaptchaRejectedErrorException, IOErrorException, RateLimitErrorException, UnexpectedErrorException, UntrustedKeyErrorException, UserErrorException {
|
||||||
|
|
||||||
public CommandException(final String message) {
|
public CommandException(final String message) {
|
||||||
super(message);
|
super(message);
|
||||||
|
|||||||
@ -916,6 +916,14 @@ public class DbusManagerImpl implements Manager {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void addUnidentifiedKeepAlive(final String token) {
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void removeUnidentifiedKeepAlive(final String token) {
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void addCallEventListener(final CallEventListener listener) {
|
public void addCallEventListener(final CallEventListener listener) {
|
||||||
// Not supported over DBus
|
// Not supported over DBus
|
||||||
|
|||||||
@ -100,6 +100,7 @@ public class DbusSignalImpl implements Signal, AutoCloseable {
|
|||||||
|
|
||||||
public void initObjects() {
|
public void initObjects() {
|
||||||
exportObjects();
|
exportObjects();
|
||||||
|
m.addUnidentifiedKeepAlive("dbus");
|
||||||
if (!noReceiveOnStart) {
|
if (!noReceiveOnStart) {
|
||||||
subscribeReceive();
|
subscribeReceive();
|
||||||
}
|
}
|
||||||
@ -116,6 +117,7 @@ public class DbusSignalImpl implements Signal, AutoCloseable {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void close() {
|
public void close() {
|
||||||
|
m.removeUnidentifiedKeepAlive("dbus");
|
||||||
if (dbusMessageHandler != null) {
|
if (dbusMessageHandler != null) {
|
||||||
m.removeReceiveHandler(dbusMessageHandler);
|
m.removeReceiveHandler(dbusMessageHandler);
|
||||||
dbusMessageHandler = null;
|
dbusMessageHandler = null;
|
||||||
@ -700,9 +702,13 @@ public class DbusSignalImpl implements Signal, AutoCloseable {
|
|||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
throw new Error.Failure(e.getMessage());
|
throw new Error.Failure(e.getMessage());
|
||||||
} catch (RateLimitException e) {
|
} catch (RateLimitException e) {
|
||||||
throw new Error.Failure(e.getMessage()
|
final var retryAfterMilliseconds = e.getRetryAfterMilliseconds();
|
||||||
+ ", retry at "
|
throw new Error.Failure(e.getMessage() + (
|
||||||
+ DateUtils.formatTimestamp(e.getNextAttemptTimestamp()));
|
retryAfterMilliseconds == null
|
||||||
|
? ""
|
||||||
|
: ", retry at " + DateUtils.formatTimestamp(System.currentTimeMillis()
|
||||||
|
+ retryAfterMilliseconds)
|
||||||
|
));
|
||||||
}
|
}
|
||||||
|
|
||||||
return numbers.stream().map(number -> registered.get(number).uuid() != null).toList();
|
return numbers.stream().map(number -> registered.get(number).uuid() != null).toList();
|
||||||
|
|||||||
@ -1,9 +1,11 @@
|
|||||||
package org.asamk.signal.json;
|
package org.asamk.signal.json;
|
||||||
|
|
||||||
|
import io.micronaut.jsonschema.JsonSchema;
|
||||||
import org.asamk.signal.manager.api.MessageEnvelope;
|
import org.asamk.signal.manager.api.MessageEnvelope;
|
||||||
|
|
||||||
import java.util.UUID;
|
import java.util.UUID;
|
||||||
|
|
||||||
|
@JsonSchema(title = "AdminDelete")
|
||||||
public record JsonAdminDelete(
|
public record JsonAdminDelete(
|
||||||
@Deprecated String targetAuthor, String targetAuthorNumber, String targetAuthorUuid, long targetSentTimestamp
|
@Deprecated String targetAuthor, String targetAuthorNumber, String targetAuthorUuid, long targetSentTimestamp
|
||||||
) {
|
) {
|
||||||
|
|||||||
@ -1,7 +1,10 @@
|
|||||||
package org.asamk.signal.json;
|
package org.asamk.signal.json;
|
||||||
|
|
||||||
|
import io.micronaut.jsonschema.JsonSchema;
|
||||||
|
|
||||||
import org.asamk.signal.manager.api.MessageEnvelope;
|
import org.asamk.signal.manager.api.MessageEnvelope;
|
||||||
|
|
||||||
|
@JsonSchema(title = "Attachment")
|
||||||
record JsonAttachment(
|
record JsonAttachment(
|
||||||
String contentType,
|
String contentType,
|
||||||
String filename,
|
String filename,
|
||||||
|
|||||||
@ -1,5 +1,8 @@
|
|||||||
package org.asamk.signal.json;
|
package org.asamk.signal.json;
|
||||||
|
|
||||||
|
import io.micronaut.jsonschema.JsonSchema;
|
||||||
|
|
||||||
|
@JsonSchema(title = "AttachmentData")
|
||||||
public record JsonAttachmentData(
|
public record JsonAttachmentData(
|
||||||
String data
|
String data
|
||||||
) {}
|
) {}
|
||||||
|
|||||||
@ -1,6 +1,7 @@
|
|||||||
package org.asamk.signal.json;
|
package org.asamk.signal.json;
|
||||||
|
|
||||||
import com.fasterxml.jackson.annotation.JsonInclude;
|
import com.fasterxml.jackson.annotation.JsonInclude;
|
||||||
|
import io.micronaut.jsonschema.JsonSchema;
|
||||||
|
|
||||||
import org.asamk.signal.manager.api.MessageEnvelope;
|
import org.asamk.signal.manager.api.MessageEnvelope;
|
||||||
|
|
||||||
@ -10,6 +11,7 @@ import java.util.List;
|
|||||||
|
|
||||||
import static org.asamk.signal.manager.util.Utils.callIdUnsigned;
|
import static org.asamk.signal.manager.util.Utils.callIdUnsigned;
|
||||||
|
|
||||||
|
@JsonSchema(title = "CallMessage")
|
||||||
record JsonCallMessage(
|
record JsonCallMessage(
|
||||||
@JsonInclude(JsonInclude.Include.NON_NULL) Offer offerMessage,
|
@JsonInclude(JsonInclude.Include.NON_NULL) Offer offerMessage,
|
||||||
@JsonInclude(JsonInclude.Include.NON_NULL) Answer answerMessage,
|
@JsonInclude(JsonInclude.Include.NON_NULL) Answer answerMessage,
|
||||||
|
|||||||
@ -1,9 +1,11 @@
|
|||||||
package org.asamk.signal.json;
|
package org.asamk.signal.json;
|
||||||
|
|
||||||
import com.fasterxml.jackson.annotation.JsonInclude;
|
import com.fasterxml.jackson.annotation.JsonInclude;
|
||||||
|
import io.micronaut.jsonschema.JsonSchema;
|
||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
|
@JsonSchema(title = "Contact")
|
||||||
public record JsonContact(
|
public record JsonContact(
|
||||||
String number,
|
String number,
|
||||||
String uuid,
|
String uuid,
|
||||||
@ -26,6 +28,7 @@ public record JsonContact(
|
|||||||
@JsonInclude(JsonInclude.Include.NON_NULL) JsonInternal internal
|
@JsonInclude(JsonInclude.Include.NON_NULL) JsonInternal internal
|
||||||
) {
|
) {
|
||||||
|
|
||||||
|
@JsonSchema(title = "Profile")
|
||||||
public record JsonProfile(
|
public record JsonProfile(
|
||||||
long lastUpdateTimestamp,
|
long lastUpdateTimestamp,
|
||||||
String givenName,
|
String givenName,
|
||||||
@ -36,6 +39,7 @@ public record JsonContact(
|
|||||||
String mobileCoinAddress
|
String mobileCoinAddress
|
||||||
) {}
|
) {}
|
||||||
|
|
||||||
|
@JsonSchema(title = "Internal")
|
||||||
public record JsonInternal(
|
public record JsonInternal(
|
||||||
List<String> capabilities,
|
List<String> capabilities,
|
||||||
String unidentifiedAccessMode,
|
String unidentifiedAccessMode,
|
||||||
|
|||||||
@ -1,8 +1,11 @@
|
|||||||
package org.asamk.signal.json;
|
package org.asamk.signal.json;
|
||||||
|
|
||||||
|
import io.micronaut.jsonschema.JsonSchema;
|
||||||
|
|
||||||
import org.asamk.signal.manager.api.MessageEnvelope;
|
import org.asamk.signal.manager.api.MessageEnvelope;
|
||||||
import org.asamk.signal.util.Util;
|
import org.asamk.signal.util.Util;
|
||||||
|
|
||||||
|
@JsonSchema(title = "ContactAddress")
|
||||||
public record JsonContactAddress(
|
public record JsonContactAddress(
|
||||||
String type,
|
String type,
|
||||||
String label,
|
String label,
|
||||||
|
|||||||
@ -1,7 +1,10 @@
|
|||||||
package org.asamk.signal.json;
|
package org.asamk.signal.json;
|
||||||
|
|
||||||
|
import io.micronaut.jsonschema.JsonSchema;
|
||||||
|
|
||||||
import org.asamk.signal.manager.api.MessageEnvelope;
|
import org.asamk.signal.manager.api.MessageEnvelope;
|
||||||
|
|
||||||
|
@JsonSchema(title = "ContactAvatar")
|
||||||
public record JsonContactAvatar(JsonAttachment attachment, boolean isProfile) {
|
public record JsonContactAvatar(JsonAttachment attachment, boolean isProfile) {
|
||||||
|
|
||||||
static JsonContactAvatar from(MessageEnvelope.Data.SharedContact.Avatar avatar) {
|
static JsonContactAvatar from(MessageEnvelope.Data.SharedContact.Avatar avatar) {
|
||||||
|
|||||||
@ -1,8 +1,11 @@
|
|||||||
package org.asamk.signal.json;
|
package org.asamk.signal.json;
|
||||||
|
|
||||||
|
import io.micronaut.jsonschema.JsonSchema;
|
||||||
|
|
||||||
import org.asamk.signal.manager.api.MessageEnvelope;
|
import org.asamk.signal.manager.api.MessageEnvelope;
|
||||||
import org.asamk.signal.util.Util;
|
import org.asamk.signal.util.Util;
|
||||||
|
|
||||||
|
@JsonSchema(title = "ContactEmail")
|
||||||
public record JsonContactEmail(String value, String type, String label) {
|
public record JsonContactEmail(String value, String type, String label) {
|
||||||
|
|
||||||
static JsonContactEmail from(MessageEnvelope.Data.SharedContact.Email email) {
|
static JsonContactEmail from(MessageEnvelope.Data.SharedContact.Email email) {
|
||||||
|
|||||||
@ -1,8 +1,11 @@
|
|||||||
package org.asamk.signal.json;
|
package org.asamk.signal.json;
|
||||||
|
|
||||||
|
import io.micronaut.jsonschema.JsonSchema;
|
||||||
|
|
||||||
import org.asamk.signal.manager.api.MessageEnvelope;
|
import org.asamk.signal.manager.api.MessageEnvelope;
|
||||||
import org.asamk.signal.util.Util;
|
import org.asamk.signal.util.Util;
|
||||||
|
|
||||||
|
@JsonSchema(title = "ContactName")
|
||||||
public record JsonContactName(
|
public record JsonContactName(
|
||||||
String nickname, String given, String family, String prefix, String suffix, String middle
|
String nickname, String given, String family, String prefix, String suffix, String middle
|
||||||
) {
|
) {
|
||||||
|
|||||||
@ -1,8 +1,11 @@
|
|||||||
package org.asamk.signal.json;
|
package org.asamk.signal.json;
|
||||||
|
|
||||||
|
import io.micronaut.jsonschema.JsonSchema;
|
||||||
|
|
||||||
import org.asamk.signal.manager.api.MessageEnvelope;
|
import org.asamk.signal.manager.api.MessageEnvelope;
|
||||||
import org.asamk.signal.util.Util;
|
import org.asamk.signal.util.Util;
|
||||||
|
|
||||||
|
@JsonSchema(title = "ContactPhone")
|
||||||
public record JsonContactPhone(String value, String type, String label) {
|
public record JsonContactPhone(String value, String type, String label) {
|
||||||
|
|
||||||
static JsonContactPhone from(MessageEnvelope.Data.SharedContact.Phone phone) {
|
static JsonContactPhone from(MessageEnvelope.Data.SharedContact.Phone phone) {
|
||||||
|
|||||||
@ -1,12 +1,14 @@
|
|||||||
package org.asamk.signal.json;
|
package org.asamk.signal.json;
|
||||||
|
|
||||||
import com.fasterxml.jackson.annotation.JsonInclude;
|
import com.fasterxml.jackson.annotation.JsonInclude;
|
||||||
|
import io.micronaut.jsonschema.JsonSchema;
|
||||||
|
|
||||||
import org.asamk.signal.manager.Manager;
|
import org.asamk.signal.manager.Manager;
|
||||||
import org.asamk.signal.manager.api.MessageEnvelope;
|
import org.asamk.signal.manager.api.MessageEnvelope;
|
||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
|
@JsonSchema(title = "DataMessage")
|
||||||
record JsonDataMessage(
|
record JsonDataMessage(
|
||||||
long timestamp,
|
long timestamp,
|
||||||
String message,
|
String message,
|
||||||
|
|||||||
@ -1,8 +1,11 @@
|
|||||||
package org.asamk.signal.json;
|
package org.asamk.signal.json;
|
||||||
|
|
||||||
|
import io.micronaut.jsonschema.JsonSchema;
|
||||||
|
|
||||||
import org.asamk.signal.manager.Manager;
|
import org.asamk.signal.manager.Manager;
|
||||||
import org.asamk.signal.manager.api.MessageEnvelope;
|
import org.asamk.signal.manager.api.MessageEnvelope;
|
||||||
|
|
||||||
|
@JsonSchema(title = "EditMessage")
|
||||||
record JsonEditMessage(long targetSentTimestamp, JsonDataMessage dataMessage) {
|
record JsonEditMessage(long targetSentTimestamp, JsonDataMessage dataMessage) {
|
||||||
|
|
||||||
static JsonEditMessage from(MessageEnvelope.Edit editMessage, Manager m) {
|
static JsonEditMessage from(MessageEnvelope.Edit editMessage, Manager m) {
|
||||||
|
|||||||
@ -1,5 +1,8 @@
|
|||||||
package org.asamk.signal.json;
|
package org.asamk.signal.json;
|
||||||
|
|
||||||
|
import io.micronaut.jsonschema.JsonSchema;
|
||||||
|
|
||||||
|
@JsonSchema(title = "Error")
|
||||||
public record JsonError(String message, String type) {
|
public record JsonError(String message, String type) {
|
||||||
|
|
||||||
public static JsonError from(Throwable exception) {
|
public static JsonError from(Throwable exception) {
|
||||||
|
|||||||
@ -1,8 +1,11 @@
|
|||||||
package org.asamk.signal.json;
|
package org.asamk.signal.json;
|
||||||
|
|
||||||
|
import io.micronaut.jsonschema.JsonSchema;
|
||||||
|
|
||||||
import org.asamk.signal.manager.Manager;
|
import org.asamk.signal.manager.Manager;
|
||||||
import org.asamk.signal.manager.api.MessageEnvelope;
|
import org.asamk.signal.manager.api.MessageEnvelope;
|
||||||
|
|
||||||
|
@JsonSchema(title = "GroupInfo")
|
||||||
record JsonGroupInfo(String groupId, String groupName, int revision, String type) {
|
record JsonGroupInfo(String groupId, String groupName, int revision, String type) {
|
||||||
|
|
||||||
static JsonGroupInfo from(MessageEnvelope.Data.GroupContext groupContext, Manager m) {
|
static JsonGroupInfo from(MessageEnvelope.Data.GroupContext groupContext, Manager m) {
|
||||||
|
|||||||
@ -1,9 +1,12 @@
|
|||||||
package org.asamk.signal.json;
|
package org.asamk.signal.json;
|
||||||
|
|
||||||
|
import io.micronaut.jsonschema.JsonSchema;
|
||||||
|
|
||||||
import org.asamk.signal.manager.api.MessageEnvelope;
|
import org.asamk.signal.manager.api.MessageEnvelope;
|
||||||
|
|
||||||
import java.util.UUID;
|
import java.util.UUID;
|
||||||
|
|
||||||
|
@JsonSchema(title = "Mention")
|
||||||
public record JsonMention(@Deprecated String name, String number, String uuid, int start, int length) {
|
public record JsonMention(@Deprecated String name, String number, String uuid, int start, int length) {
|
||||||
|
|
||||||
static JsonMention from(MessageEnvelope.Data.Mention mention) {
|
static JsonMention from(MessageEnvelope.Data.Mention mention) {
|
||||||
|
|||||||
@ -1,6 +1,7 @@
|
|||||||
package org.asamk.signal.json;
|
package org.asamk.signal.json;
|
||||||
|
|
||||||
import com.fasterxml.jackson.annotation.JsonInclude;
|
import com.fasterxml.jackson.annotation.JsonInclude;
|
||||||
|
import io.micronaut.jsonschema.JsonSchema;
|
||||||
|
|
||||||
import org.asamk.signal.manager.Manager;
|
import org.asamk.signal.manager.Manager;
|
||||||
import org.asamk.signal.manager.api.MessageEnvelope;
|
import org.asamk.signal.manager.api.MessageEnvelope;
|
||||||
@ -10,6 +11,7 @@ import org.asamk.signal.manager.api.UntrustedIdentityException;
|
|||||||
|
|
||||||
import java.util.UUID;
|
import java.util.UUID;
|
||||||
|
|
||||||
|
@JsonSchema(title = "MessageEnvelope")
|
||||||
public record JsonMessageEnvelope(
|
public record JsonMessageEnvelope(
|
||||||
@Deprecated String source,
|
@Deprecated String source,
|
||||||
String sourceNumber,
|
String sourceNumber,
|
||||||
|
|||||||
@ -1,7 +1,10 @@
|
|||||||
package org.asamk.signal.json;
|
package org.asamk.signal.json;
|
||||||
|
|
||||||
|
import io.micronaut.jsonschema.JsonSchema;
|
||||||
|
|
||||||
import org.asamk.signal.manager.api.MessageEnvelope;
|
import org.asamk.signal.manager.api.MessageEnvelope;
|
||||||
|
|
||||||
|
@JsonSchema(title = "Payment")
|
||||||
public record JsonPayment(String note, byte[] receipt) {
|
public record JsonPayment(String note, byte[] receipt) {
|
||||||
|
|
||||||
static JsonPayment from(MessageEnvelope.Data.Payment payment) {
|
static JsonPayment from(MessageEnvelope.Data.Payment payment) {
|
||||||
|
|||||||
@ -1,9 +1,12 @@
|
|||||||
package org.asamk.signal.json;
|
package org.asamk.signal.json;
|
||||||
|
|
||||||
|
import io.micronaut.jsonschema.JsonSchema;
|
||||||
|
|
||||||
import org.asamk.signal.manager.api.MessageEnvelope;
|
import org.asamk.signal.manager.api.MessageEnvelope;
|
||||||
|
|
||||||
import java.util.UUID;
|
import java.util.UUID;
|
||||||
|
|
||||||
|
@JsonSchema(title = "PinMessage")
|
||||||
public record JsonPinMessage(
|
public record JsonPinMessage(
|
||||||
@Deprecated String targetAuthor,
|
@Deprecated String targetAuthor,
|
||||||
String targetAuthorNumber,
|
String targetAuthorNumber,
|
||||||
|
|||||||
@ -1,9 +1,12 @@
|
|||||||
package org.asamk.signal.json;
|
package org.asamk.signal.json;
|
||||||
|
|
||||||
|
import io.micronaut.jsonschema.JsonSchema;
|
||||||
|
|
||||||
import org.asamk.signal.manager.api.MessageEnvelope;
|
import org.asamk.signal.manager.api.MessageEnvelope;
|
||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
|
@JsonSchema(title = "PollCreate")
|
||||||
public record JsonPollCreate(
|
public record JsonPollCreate(
|
||||||
String question, boolean allowMultiple, List<String> options
|
String question, boolean allowMultiple, List<String> options
|
||||||
) {
|
) {
|
||||||
|
|||||||
@ -1,7 +1,10 @@
|
|||||||
package org.asamk.signal.json;
|
package org.asamk.signal.json;
|
||||||
|
|
||||||
|
import io.micronaut.jsonschema.JsonSchema;
|
||||||
|
|
||||||
import org.asamk.signal.manager.api.MessageEnvelope;
|
import org.asamk.signal.manager.api.MessageEnvelope;
|
||||||
|
|
||||||
|
@JsonSchema(title = "PollTerminate")
|
||||||
public record JsonPollTerminate(long targetSentTimestamp) {
|
public record JsonPollTerminate(long targetSentTimestamp) {
|
||||||
|
|
||||||
static JsonPollTerminate from(MessageEnvelope.Data.PollTerminate pollTerminate) {
|
static JsonPollTerminate from(MessageEnvelope.Data.PollTerminate pollTerminate) {
|
||||||
|
|||||||
@ -1,10 +1,13 @@
|
|||||||
package org.asamk.signal.json;
|
package org.asamk.signal.json;
|
||||||
|
|
||||||
|
import io.micronaut.jsonschema.JsonSchema;
|
||||||
|
|
||||||
import org.asamk.signal.manager.api.MessageEnvelope;
|
import org.asamk.signal.manager.api.MessageEnvelope;
|
||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.UUID;
|
import java.util.UUID;
|
||||||
|
|
||||||
|
@JsonSchema(title = "PollVote")
|
||||||
public record JsonPollVote(
|
public record JsonPollVote(
|
||||||
@Deprecated String author,
|
@Deprecated String author,
|
||||||
String authorNumber,
|
String authorNumber,
|
||||||
|
|||||||
@ -1,7 +1,10 @@
|
|||||||
package org.asamk.signal.json;
|
package org.asamk.signal.json;
|
||||||
|
|
||||||
|
import io.micronaut.jsonschema.JsonSchema;
|
||||||
|
|
||||||
import org.asamk.signal.manager.api.MessageEnvelope;
|
import org.asamk.signal.manager.api.MessageEnvelope;
|
||||||
|
|
||||||
|
@JsonSchema(title = "Preview")
|
||||||
public record JsonPreview(String url, String title, String description, JsonAttachment image) {
|
public record JsonPreview(String url, String title, String description, JsonAttachment image) {
|
||||||
|
|
||||||
static JsonPreview from(MessageEnvelope.Data.Preview preview) {
|
static JsonPreview from(MessageEnvelope.Data.Preview preview) {
|
||||||
|
|||||||
@ -1,12 +1,14 @@
|
|||||||
package org.asamk.signal.json;
|
package org.asamk.signal.json;
|
||||||
|
|
||||||
import com.fasterxml.jackson.annotation.JsonInclude;
|
import com.fasterxml.jackson.annotation.JsonInclude;
|
||||||
|
import io.micronaut.jsonschema.JsonSchema;
|
||||||
|
|
||||||
import org.asamk.signal.manager.api.MessageEnvelope;
|
import org.asamk.signal.manager.api.MessageEnvelope;
|
||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.UUID;
|
import java.util.UUID;
|
||||||
|
|
||||||
|
@JsonSchema(title = "Quote")
|
||||||
public record JsonQuote(
|
public record JsonQuote(
|
||||||
long id,
|
long id,
|
||||||
@Deprecated String author,
|
@Deprecated String author,
|
||||||
|
|||||||
@ -1,9 +1,11 @@
|
|||||||
package org.asamk.signal.json;
|
package org.asamk.signal.json;
|
||||||
|
|
||||||
import com.fasterxml.jackson.annotation.JsonInclude;
|
import com.fasterxml.jackson.annotation.JsonInclude;
|
||||||
|
import io.micronaut.jsonschema.JsonSchema;
|
||||||
|
|
||||||
import org.asamk.signal.manager.api.MessageEnvelope;
|
import org.asamk.signal.manager.api.MessageEnvelope;
|
||||||
|
|
||||||
|
@JsonSchema(title = "QuotedAttachment")
|
||||||
public record JsonQuotedAttachment(
|
public record JsonQuotedAttachment(
|
||||||
String contentType, String filename, @JsonInclude(JsonInclude.Include.NON_NULL) JsonAttachment thumbnail
|
String contentType, String filename, @JsonInclude(JsonInclude.Include.NON_NULL) JsonAttachment thumbnail
|
||||||
) {
|
) {
|
||||||
|
|||||||
@ -1,9 +1,12 @@
|
|||||||
package org.asamk.signal.json;
|
package org.asamk.signal.json;
|
||||||
|
|
||||||
|
import io.micronaut.jsonschema.JsonSchema;
|
||||||
|
|
||||||
import org.asamk.signal.manager.api.MessageEnvelope;
|
import org.asamk.signal.manager.api.MessageEnvelope;
|
||||||
|
|
||||||
import java.util.UUID;
|
import java.util.UUID;
|
||||||
|
|
||||||
|
@JsonSchema(title = "Reaction")
|
||||||
public record JsonReaction(
|
public record JsonReaction(
|
||||||
String emoji,
|
String emoji,
|
||||||
@Deprecated String targetAuthor,
|
@Deprecated String targetAuthor,
|
||||||
|
|||||||
@ -1,9 +1,12 @@
|
|||||||
package org.asamk.signal.json;
|
package org.asamk.signal.json;
|
||||||
|
|
||||||
|
import io.micronaut.jsonschema.JsonSchema;
|
||||||
|
|
||||||
import org.asamk.signal.manager.api.MessageEnvelope;
|
import org.asamk.signal.manager.api.MessageEnvelope;
|
||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
|
@JsonSchema(title = "ReceiptMessage")
|
||||||
record JsonReceiptMessage(long when, boolean isDelivery, boolean isRead, boolean isViewed, List<Long> timestamps) {
|
record JsonReceiptMessage(long when, boolean isDelivery, boolean isRead, boolean isViewed, List<Long> timestamps) {
|
||||||
|
|
||||||
static JsonReceiptMessage from(MessageEnvelope.Receipt receiptMessage) {
|
static JsonReceiptMessage from(MessageEnvelope.Receipt receiptMessage) {
|
||||||
|
|||||||
@ -1,9 +1,12 @@
|
|||||||
package org.asamk.signal.json;
|
package org.asamk.signal.json;
|
||||||
|
|
||||||
|
import io.micronaut.jsonschema.JsonSchema;
|
||||||
|
|
||||||
import org.asamk.signal.manager.api.RecipientAddress;
|
import org.asamk.signal.manager.api.RecipientAddress;
|
||||||
|
|
||||||
import java.util.UUID;
|
import java.util.UUID;
|
||||||
|
|
||||||
|
@JsonSchema(title = "RecipientAddress")
|
||||||
public record JsonRecipientAddress(String uuid, String number, String username) {
|
public record JsonRecipientAddress(String uuid, String number, String username) {
|
||||||
|
|
||||||
public static JsonRecipientAddress from(RecipientAddress address) {
|
public static JsonRecipientAddress from(RecipientAddress address) {
|
||||||
|
|||||||
@ -1,3 +1,6 @@
|
|||||||
package org.asamk.signal.json;
|
package org.asamk.signal.json;
|
||||||
|
|
||||||
|
import io.micronaut.jsonschema.JsonSchema;
|
||||||
|
|
||||||
|
@JsonSchema(title = "RemoteDelete")
|
||||||
record JsonRemoteDelete(long timestamp) {}
|
record JsonRemoteDelete(long timestamp) {}
|
||||||
|
|||||||
@ -1,10 +1,12 @@
|
|||||||
package org.asamk.signal.json;
|
package org.asamk.signal.json;
|
||||||
|
|
||||||
import com.fasterxml.jackson.annotation.JsonInclude;
|
import com.fasterxml.jackson.annotation.JsonInclude;
|
||||||
|
import io.micronaut.jsonschema.JsonSchema;
|
||||||
|
|
||||||
import org.asamk.signal.manager.api.GroupId;
|
import org.asamk.signal.manager.api.GroupId;
|
||||||
import org.asamk.signal.manager.api.SendMessageResult;
|
import org.asamk.signal.manager.api.SendMessageResult;
|
||||||
|
|
||||||
|
@JsonSchema(title = "SendMessageResult")
|
||||||
public record JsonSendMessageResult(
|
public record JsonSendMessageResult(
|
||||||
JsonRecipientAddress recipientAddress,
|
JsonRecipientAddress recipientAddress,
|
||||||
@JsonInclude(JsonInclude.Include.NON_NULL) String groupId,
|
@JsonInclude(JsonInclude.Include.NON_NULL) String groupId,
|
||||||
@ -18,6 +20,7 @@ public record JsonSendMessageResult(
|
|||||||
}
|
}
|
||||||
|
|
||||||
public static JsonSendMessageResult from(SendMessageResult result, GroupId groupId) {
|
public static JsonSendMessageResult from(SendMessageResult result, GroupId groupId) {
|
||||||
|
final var rateLimitRetryAfterMilliseconds = result.rateLimitRetryAfterMilliseconds();
|
||||||
return new JsonSendMessageResult(JsonRecipientAddress.from(result.address()),
|
return new JsonSendMessageResult(JsonRecipientAddress.from(result.address()),
|
||||||
groupId != null ? groupId.toBase64() : null,
|
groupId != null ? groupId.toBase64() : null,
|
||||||
result.isSuccess()
|
result.isSuccess()
|
||||||
@ -32,7 +35,7 @@ public record JsonSendMessageResult(
|
|||||||
? Type.INVALID_PRE_KEY_FAILURE
|
? Type.INVALID_PRE_KEY_FAILURE
|
||||||
: Type.IDENTITY_FAILURE,
|
: Type.IDENTITY_FAILURE,
|
||||||
result.proofRequiredFailure() != null ? result.proofRequiredFailure().getToken() : null,
|
result.proofRequiredFailure() != null ? result.proofRequiredFailure().getToken() : null,
|
||||||
result.proofRequiredFailure() != null ? result.proofRequiredFailure().getRetryAfterSeconds() : null);
|
rateLimitRetryAfterMilliseconds == null ? null : Math.ceilDiv(rateLimitRetryAfterMilliseconds, 1000L));
|
||||||
}
|
}
|
||||||
|
|
||||||
public enum Type {
|
public enum Type {
|
||||||
|
|||||||
@ -1,11 +1,13 @@
|
|||||||
package org.asamk.signal.json;
|
package org.asamk.signal.json;
|
||||||
|
|
||||||
import com.fasterxml.jackson.annotation.JsonInclude;
|
import com.fasterxml.jackson.annotation.JsonInclude;
|
||||||
|
import io.micronaut.jsonschema.JsonSchema;
|
||||||
|
|
||||||
import org.asamk.signal.manager.api.MessageEnvelope;
|
import org.asamk.signal.manager.api.MessageEnvelope;
|
||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
|
@JsonSchema(title = "SharedContact")
|
||||||
public record JsonSharedContact(
|
public record JsonSharedContact(
|
||||||
JsonContactName name,
|
JsonContactName name,
|
||||||
@JsonInclude(JsonInclude.Include.NON_NULL) JsonContactAvatar avatar,
|
@JsonInclude(JsonInclude.Include.NON_NULL) JsonContactAvatar avatar,
|
||||||
|
|||||||
@ -1,8 +1,11 @@
|
|||||||
package org.asamk.signal.json;
|
package org.asamk.signal.json;
|
||||||
|
|
||||||
|
import io.micronaut.jsonschema.JsonSchema;
|
||||||
|
|
||||||
import org.asamk.signal.manager.api.MessageEnvelope;
|
import org.asamk.signal.manager.api.MessageEnvelope;
|
||||||
import org.asamk.signal.util.Hex;
|
import org.asamk.signal.util.Hex;
|
||||||
|
|
||||||
|
@JsonSchema(title = "Sticker")
|
||||||
public record JsonSticker(String packId, int stickerId) {
|
public record JsonSticker(String packId, int stickerId) {
|
||||||
|
|
||||||
static JsonSticker from(MessageEnvelope.Data.Sticker sticker) {
|
static JsonSticker from(MessageEnvelope.Data.Sticker sticker) {
|
||||||
|
|||||||
@ -1,9 +1,12 @@
|
|||||||
package org.asamk.signal.json;
|
package org.asamk.signal.json;
|
||||||
|
|
||||||
|
import io.micronaut.jsonschema.JsonSchema;
|
||||||
|
|
||||||
import org.asamk.signal.manager.api.MessageEnvelope;
|
import org.asamk.signal.manager.api.MessageEnvelope;
|
||||||
|
|
||||||
import java.util.UUID;
|
import java.util.UUID;
|
||||||
|
|
||||||
|
@JsonSchema(title = "StoryContext")
|
||||||
record JsonStoryContext(
|
record JsonStoryContext(
|
||||||
String authorNumber, String authorUuid, long sentTimestamp
|
String authorNumber, String authorUuid, long sentTimestamp
|
||||||
) {
|
) {
|
||||||
|
|||||||
@ -1,6 +1,7 @@
|
|||||||
package org.asamk.signal.json;
|
package org.asamk.signal.json;
|
||||||
|
|
||||||
import com.fasterxml.jackson.annotation.JsonInclude;
|
import com.fasterxml.jackson.annotation.JsonInclude;
|
||||||
|
import io.micronaut.jsonschema.JsonSchema;
|
||||||
|
|
||||||
import org.asamk.signal.manager.api.Color;
|
import org.asamk.signal.manager.api.Color;
|
||||||
import org.asamk.signal.manager.api.GroupId;
|
import org.asamk.signal.manager.api.GroupId;
|
||||||
@ -8,6 +9,7 @@ import org.asamk.signal.manager.api.MessageEnvelope;
|
|||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
|
@JsonSchema(title = "StoryMessage")
|
||||||
record JsonStoryMessage(
|
record JsonStoryMessage(
|
||||||
boolean allowsReplies,
|
boolean allowsReplies,
|
||||||
@JsonInclude(JsonInclude.Include.NON_NULL) String groupId,
|
@JsonInclude(JsonInclude.Include.NON_NULL) String groupId,
|
||||||
|
|||||||
@ -2,6 +2,7 @@ package org.asamk.signal.json;
|
|||||||
|
|
||||||
import com.fasterxml.jackson.annotation.JsonInclude;
|
import com.fasterxml.jackson.annotation.JsonInclude;
|
||||||
import com.fasterxml.jackson.annotation.JsonUnwrapped;
|
import com.fasterxml.jackson.annotation.JsonUnwrapped;
|
||||||
|
import io.micronaut.jsonschema.JsonSchema;
|
||||||
|
|
||||||
import org.asamk.signal.manager.Manager;
|
import org.asamk.signal.manager.Manager;
|
||||||
import org.asamk.signal.manager.api.MessageEnvelope;
|
import org.asamk.signal.manager.api.MessageEnvelope;
|
||||||
@ -9,6 +10,7 @@ import org.asamk.signal.manager.api.RecipientAddress;
|
|||||||
|
|
||||||
import java.util.UUID;
|
import java.util.UUID;
|
||||||
|
|
||||||
|
@JsonSchema(title = "SyncDataMessage")
|
||||||
record JsonSyncDataMessage(
|
record JsonSyncDataMessage(
|
||||||
@Deprecated String destination,
|
@Deprecated String destination,
|
||||||
String destinationNumber,
|
String destinationNumber,
|
||||||
|
|||||||
@ -9,12 +9,15 @@ import org.asamk.signal.manager.api.RecipientAddress;
|
|||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
|
import io.micronaut.jsonschema.JsonSchema;
|
||||||
|
|
||||||
enum JsonSyncMessageType {
|
enum JsonSyncMessageType {
|
||||||
CONTACTS_SYNC,
|
CONTACTS_SYNC,
|
||||||
GROUPS_SYNC,
|
GROUPS_SYNC,
|
||||||
REQUEST_SYNC
|
REQUEST_SYNC
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@JsonSchema(title = "SyncMessage")
|
||||||
record JsonSyncMessage(
|
record JsonSyncMessage(
|
||||||
@JsonInclude(JsonInclude.Include.NON_NULL) JsonSyncDataMessage sentMessage,
|
@JsonInclude(JsonInclude.Include.NON_NULL) JsonSyncDataMessage sentMessage,
|
||||||
@JsonInclude(JsonInclude.Include.NON_NULL) JsonSyncStoryMessage sentStoryMessage,
|
@JsonInclude(JsonInclude.Include.NON_NULL) JsonSyncStoryMessage sentStoryMessage,
|
||||||
|
|||||||
@ -1,9 +1,12 @@
|
|||||||
package org.asamk.signal.json;
|
package org.asamk.signal.json;
|
||||||
|
|
||||||
|
import io.micronaut.jsonschema.JsonSchema;
|
||||||
|
|
||||||
import org.asamk.signal.manager.api.MessageEnvelope;
|
import org.asamk.signal.manager.api.MessageEnvelope;
|
||||||
|
|
||||||
import java.util.UUID;
|
import java.util.UUID;
|
||||||
|
|
||||||
|
@JsonSchema(title = "SyncReadMessage")
|
||||||
record JsonSyncReadMessage(
|
record JsonSyncReadMessage(
|
||||||
@Deprecated String sender, String senderNumber, String senderUuid, long timestamp
|
@Deprecated String sender, String senderNumber, String senderUuid, long timestamp
|
||||||
) {
|
) {
|
||||||
|
|||||||
@ -1,11 +1,13 @@
|
|||||||
package org.asamk.signal.json;
|
package org.asamk.signal.json;
|
||||||
|
|
||||||
import com.fasterxml.jackson.annotation.JsonUnwrapped;
|
import com.fasterxml.jackson.annotation.JsonUnwrapped;
|
||||||
|
import io.micronaut.jsonschema.JsonSchema;
|
||||||
|
|
||||||
import org.asamk.signal.manager.api.MessageEnvelope;
|
import org.asamk.signal.manager.api.MessageEnvelope;
|
||||||
|
|
||||||
import java.util.UUID;
|
import java.util.UUID;
|
||||||
|
|
||||||
|
@JsonSchema(title = "SyncStoryMessage")
|
||||||
record JsonSyncStoryMessage(
|
record JsonSyncStoryMessage(
|
||||||
String destinationNumber, String destinationUuid, @JsonUnwrapped JsonStoryMessage dataMessage
|
String destinationNumber, String destinationUuid, @JsonUnwrapped JsonStoryMessage dataMessage
|
||||||
) {
|
) {
|
||||||
|
|||||||
@ -1,7 +1,10 @@
|
|||||||
package org.asamk.signal.json;
|
package org.asamk.signal.json;
|
||||||
|
|
||||||
|
import io.micronaut.jsonschema.JsonSchema;
|
||||||
|
|
||||||
import org.asamk.signal.manager.api.TextStyle;
|
import org.asamk.signal.manager.api.TextStyle;
|
||||||
|
|
||||||
|
@JsonSchema(title = "TextStyle")
|
||||||
public record JsonTextStyle(String style, int start, int length) {
|
public record JsonTextStyle(String style, int start, int length) {
|
||||||
|
|
||||||
static JsonTextStyle from(TextStyle textStyle) {
|
static JsonTextStyle from(TextStyle textStyle) {
|
||||||
|
|||||||
@ -1,10 +1,12 @@
|
|||||||
package org.asamk.signal.json;
|
package org.asamk.signal.json;
|
||||||
|
|
||||||
import com.fasterxml.jackson.annotation.JsonInclude;
|
import com.fasterxml.jackson.annotation.JsonInclude;
|
||||||
|
import io.micronaut.jsonschema.JsonSchema;
|
||||||
|
|
||||||
import org.asamk.signal.manager.api.GroupId;
|
import org.asamk.signal.manager.api.GroupId;
|
||||||
import org.asamk.signal.manager.api.MessageEnvelope;
|
import org.asamk.signal.manager.api.MessageEnvelope;
|
||||||
|
|
||||||
|
@JsonSchema(title = "TypingMessage")
|
||||||
record JsonTypingMessage(
|
record JsonTypingMessage(
|
||||||
String action, long timestamp, @JsonInclude(JsonInclude.Include.NON_NULL) String groupId
|
String action, long timestamp, @JsonInclude(JsonInclude.Include.NON_NULL) String groupId
|
||||||
) {
|
) {
|
||||||
|
|||||||
@ -1,9 +1,12 @@
|
|||||||
package org.asamk.signal.json;
|
package org.asamk.signal.json;
|
||||||
|
|
||||||
|
import io.micronaut.jsonschema.JsonSchema;
|
||||||
|
|
||||||
import org.asamk.signal.manager.api.MessageEnvelope;
|
import org.asamk.signal.manager.api.MessageEnvelope;
|
||||||
|
|
||||||
import java.util.UUID;
|
import java.util.UUID;
|
||||||
|
|
||||||
|
@JsonSchema(title = "UnpinMessage")
|
||||||
public record JsonUnpinMessage(
|
public record JsonUnpinMessage(
|
||||||
@Deprecated String targetAuthor, String targetAuthorNumber, String targetAuthorUuid, long targetSentTimestamp
|
@Deprecated String targetAuthor, String targetAuthorNumber, String targetAuthorUuid, long targetSentTimestamp
|
||||||
) {
|
) {
|
||||||
|
|||||||
@ -12,6 +12,7 @@ import org.asamk.signal.commands.Command;
|
|||||||
import org.asamk.signal.commands.JsonRpcMultiCommand;
|
import org.asamk.signal.commands.JsonRpcMultiCommand;
|
||||||
import org.asamk.signal.commands.JsonRpcRegistrationCommand;
|
import org.asamk.signal.commands.JsonRpcRegistrationCommand;
|
||||||
import org.asamk.signal.commands.JsonRpcSingleCommand;
|
import org.asamk.signal.commands.JsonRpcSingleCommand;
|
||||||
|
import org.asamk.signal.commands.exceptions.CaptchaRejectedErrorException;
|
||||||
import org.asamk.signal.commands.exceptions.CommandException;
|
import org.asamk.signal.commands.exceptions.CommandException;
|
||||||
import org.asamk.signal.commands.exceptions.IOErrorException;
|
import org.asamk.signal.commands.exceptions.IOErrorException;
|
||||||
import org.asamk.signal.commands.exceptions.RateLimitErrorException;
|
import org.asamk.signal.commands.exceptions.RateLimitErrorException;
|
||||||
@ -39,6 +40,7 @@ public class SignalJsonRpcCommandHandler {
|
|||||||
private static final int IO_ERROR = -3;
|
private static final int IO_ERROR = -3;
|
||||||
private static final int UNTRUSTED_KEY_ERROR = -4;
|
private static final int UNTRUSTED_KEY_ERROR = -4;
|
||||||
private static final int RATELIMIT_ERROR = -5;
|
private static final int RATELIMIT_ERROR = -5;
|
||||||
|
private static final int CAPTCHA_REJECTED_ERROR = -6;
|
||||||
|
|
||||||
private final Manager m;
|
private final Manager m;
|
||||||
private final MultiAccountManager c;
|
private final MultiAccountManager c;
|
||||||
@ -258,6 +260,10 @@ public class SignalJsonRpcCommandHandler {
|
|||||||
case RateLimitErrorException e -> throw new JsonRpcException(new JsonRpcResponse.Error(RATELIMIT_ERROR,
|
case RateLimitErrorException e -> throw new JsonRpcException(new JsonRpcResponse.Error(RATELIMIT_ERROR,
|
||||||
e.getMessage(),
|
e.getMessage(),
|
||||||
getErrorDataNode(objectMapper, result)));
|
getErrorDataNode(objectMapper, result)));
|
||||||
|
case CaptchaRejectedErrorException e -> throw new JsonRpcException(new JsonRpcResponse.Error(
|
||||||
|
CAPTCHA_REJECTED_ERROR,
|
||||||
|
e.getMessage(),
|
||||||
|
getErrorDataNode(objectMapper, result)));
|
||||||
case UnexpectedErrorException e -> {
|
case UnexpectedErrorException e -> {
|
||||||
logger.error("Command execution failed with unexpected error", e);
|
logger.error("Command execution failed with unexpected error", e);
|
||||||
throw new JsonRpcException(new JsonRpcResponse.Error(JsonRpcResponse.Error.INTERNAL_ERROR,
|
throw new JsonRpcException(new JsonRpcResponse.Error(JsonRpcResponse.Error.INTERNAL_ERROR,
|
||||||
|
|||||||
@ -25,10 +25,12 @@ import org.slf4j.Logger;
|
|||||||
import org.slf4j.LoggerFactory;
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
import java.nio.channels.ClosedChannelException;
|
import java.nio.channels.ClosedChannelException;
|
||||||
|
import java.util.ArrayList;
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
import java.util.UUID;
|
||||||
import java.util.concurrent.atomic.AtomicInteger;
|
import java.util.concurrent.atomic.AtomicInteger;
|
||||||
import java.util.function.Supplier;
|
import java.util.function.Supplier;
|
||||||
|
|
||||||
@ -43,6 +45,9 @@ public class SignalJsonRpcDispatcherHandler {
|
|||||||
|
|
||||||
private final Map<Integer, List<Pair<Manager, Manager.ReceiveMessageHandler>>> receiveHandlers = new HashMap<>();
|
private final Map<Integer, List<Pair<Manager, Manager.ReceiveMessageHandler>>> receiveHandlers = new HashMap<>();
|
||||||
private final Map<Integer, List<Pair<Manager, Manager.CallEventListener>>> callEventHandlers = new HashMap<>();
|
private final Map<Integer, List<Pair<Manager, Manager.CallEventListener>>> callEventHandlers = new HashMap<>();
|
||||||
|
private final String connectionKeepAliveToken = "jsonrpc-" + UUID.randomUUID();
|
||||||
|
private final List<Manager> keepAliveManagers = new ArrayList<>();
|
||||||
|
private boolean connectionActive = true;
|
||||||
private SignalJsonRpcCommandHandler commandHandler;
|
private SignalJsonRpcCommandHandler commandHandler;
|
||||||
|
|
||||||
public SignalJsonRpcDispatcherHandler(
|
public SignalJsonRpcDispatcherHandler(
|
||||||
@ -69,6 +74,10 @@ public class SignalJsonRpcDispatcherHandler {
|
|||||||
c.addOnManagerAddedHandler(m -> callEventHandlers.forEach((subscriptionId, handlers) -> handlers.add(
|
c.addOnManagerAddedHandler(m -> callEventHandlers.forEach((subscriptionId, handlers) -> handlers.add(
|
||||||
createCallEventHandler(m, subscriptionId))));
|
createCallEventHandler(m, subscriptionId))));
|
||||||
|
|
||||||
|
c.getManagers().forEach(this::registerKeepAlive);
|
||||||
|
c.addOnManagerAddedHandler(this::registerKeepAlive);
|
||||||
|
c.addOnManagerRemovedHandler(this::unregisterKeepAlive);
|
||||||
|
|
||||||
handleConnection();
|
handleConnection();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -82,6 +91,8 @@ public class SignalJsonRpcDispatcherHandler {
|
|||||||
final var currentThread = Thread.currentThread();
|
final var currentThread = Thread.currentThread();
|
||||||
m.addClosedListener(currentThread::interrupt);
|
m.addClosedListener(currentThread::interrupt);
|
||||||
|
|
||||||
|
registerKeepAlive(m);
|
||||||
|
|
||||||
handleConnection();
|
handleConnection();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -200,14 +211,29 @@ public class SignalJsonRpcDispatcherHandler {
|
|||||||
subscriptionId.ifPresent(this::unsubscribeReceive);
|
subscriptionId.ifPresent(this::unsubscribeReceive);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void registerKeepAlive(final Manager m) {
|
||||||
|
if (!connectionActive) return;
|
||||||
|
m.addUnidentifiedKeepAlive(connectionKeepAliveToken);
|
||||||
|
keepAliveManagers.add(m);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void unregisterKeepAlive(final Manager m) {
|
||||||
|
if (!connectionActive) return;
|
||||||
|
m.removeUnidentifiedKeepAlive(connectionKeepAliveToken);
|
||||||
|
keepAliveManagers.remove(m);
|
||||||
|
}
|
||||||
|
|
||||||
private void handleConnection() {
|
private void handleConnection() {
|
||||||
try {
|
try {
|
||||||
jsonRpcReader.readMessages((method, params) -> commandHandler.handleRequest(objectMapper, method, params),
|
jsonRpcReader.readMessages((method, params) -> commandHandler.handleRequest(objectMapper, method, params),
|
||||||
response -> logger.debug("Received unexpected response for id {}", response.getId()));
|
response -> logger.debug("Received unexpected response for id {}", response.getId()));
|
||||||
} finally {
|
} finally {
|
||||||
|
connectionActive = false;
|
||||||
receiveHandlers.forEach((_subscriptionId, handlers) -> handlers.forEach(this::unsubscribeReceiveHandler));
|
receiveHandlers.forEach((_subscriptionId, handlers) -> handlers.forEach(this::unsubscribeReceiveHandler));
|
||||||
receiveHandlers.clear();
|
receiveHandlers.clear();
|
||||||
unsubscribeAllCallEvents();
|
unsubscribeAllCallEvents();
|
||||||
|
keepAliveManagers.forEach(m -> m.removeUnidentifiedKeepAlive(connectionKeepAliveToken));
|
||||||
|
keepAliveManagers.clear();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -129,16 +129,19 @@ public class CommandUtil {
|
|||||||
} else {
|
} else {
|
||||||
message = "Invalid captcha given.";
|
message = "Invalid captcha given.";
|
||||||
}
|
}
|
||||||
if (e.getNextAttemptTimestamp() > 0) {
|
if (e.getNextVerificationAttemptMilliseconds() > 0) {
|
||||||
message += "\nNext Captcha may be provided at " + DateUtils.formatTimestamp(e.getNextAttemptTimestamp());
|
message += "\nNext Captcha may be provided at " + DateUtils.formatTimestamp(System.currentTimeMillis()
|
||||||
|
+ e.getNextVerificationAttemptMilliseconds());
|
||||||
}
|
}
|
||||||
return message;
|
return message;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static String getRateLimitMessage(final RateLimitException e) {
|
public static String getRateLimitMessage(final RateLimitException e) {
|
||||||
String message = "Rate limit reached";
|
String message = "Rate limit reached";
|
||||||
if (e.getNextAttemptTimestamp() > 0) {
|
final var retryAfterMilliseconds = e.getRetryAfterMilliseconds();
|
||||||
message += "\nNext attempt may be tried at " + DateUtils.formatTimestamp(e.getNextAttemptTimestamp());
|
if (retryAfterMilliseconds != null) {
|
||||||
|
message += "\nNext attempt may be tried at " + DateUtils.formatTimestamp(System.currentTimeMillis()
|
||||||
|
+ retryAfterMilliseconds);
|
||||||
}
|
}
|
||||||
return message;
|
return message;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -59,8 +59,10 @@ public class SendMessageResultUtils {
|
|||||||
if (sendMessageResults.hasOnlyUntrustedIdentity()) {
|
if (sendMessageResults.hasOnlyUntrustedIdentity()) {
|
||||||
throw new UntrustedKeyErrorException("Failed to send message due to untrusted identities");
|
throw new UntrustedKeyErrorException("Failed to send message due to untrusted identities");
|
||||||
} else if (sendMessageResults.hasOnlyRateLimitFailure()) {
|
} else if (sendMessageResults.hasOnlyRateLimitFailure()) {
|
||||||
|
final var retryAfter = sendMessageResults.maxRateLimitRetryAfterMilliseconds();
|
||||||
|
final var nextAttempt = retryAfter == null ? 0L : System.currentTimeMillis() + retryAfter;
|
||||||
throw new RateLimitErrorException("Failed to send message due to rate limiting",
|
throw new RateLimitErrorException("Failed to send message due to rate limiting",
|
||||||
new RateLimitException(0));
|
new RateLimitException(nextAttempt));
|
||||||
} else {
|
} else {
|
||||||
throw new UserErrorException("Failed to send message");
|
throw new UserErrorException("Failed to send message");
|
||||||
}
|
}
|
||||||
@ -106,11 +108,14 @@ public class SendMessageResultUtils {
|
|||||||
.map(ProofRequiredException.Option::toString)
|
.map(ProofRequiredException.Option::toString)
|
||||||
.collect(Collectors.joining(", ")),
|
.collect(Collectors.joining(", ")),
|
||||||
failure.getToken(),
|
failure.getToken(),
|
||||||
failure.getRetryAfterSeconds());
|
Math.ceilDiv(failure.getRetryAfterMilliseconds(), 1000L));
|
||||||
} else if (result.isNetworkFailure()) {
|
} else if (result.isNetworkFailure()) {
|
||||||
return String.format("Network failure for \"%s\"", identifier);
|
return String.format("Network failure for \"%s\"", identifier);
|
||||||
} else if (result.isRateLimitFailure()) {
|
} else if (result.isRateLimitFailure()) {
|
||||||
return String.format("Rate limit failure for \"%s\"", identifier);
|
final var retryAfter = result.rateLimitRetryAfterMilliseconds();
|
||||||
|
return retryAfter != null ? String.format("Rate limit failure for \"%s\", retry after %d seconds",
|
||||||
|
identifier,
|
||||||
|
Math.ceilDiv(retryAfter, 1000L)) : String.format("Rate limit failure for \"%s\"", identifier);
|
||||||
} else if (result.isUnregisteredFailure()) {
|
} else if (result.isUnregisteredFailure()) {
|
||||||
return String.format("Unregistered user \"%s\"", identifier);
|
return String.format("Unregistered user \"%s\"", identifier);
|
||||||
} else if (result.isIdentityFailure()) {
|
} else if (result.isIdentityFailure()) {
|
||||||
|
|||||||
@ -1564,6 +1564,9 @@
|
|||||||
}
|
}
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"type": "kotlin.reflect.jvm.internal.impl.km.jvm.internal.JvmMetadataExtensions"
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"type": "kotlin.reflect.jvm.internal.impl.load.java.ErasedOverridabilityCondition"
|
"type": "kotlin.reflect.jvm.internal.impl.load.java.ErasedOverridabilityCondition"
|
||||||
},
|
},
|
||||||
@ -1626,6 +1629,9 @@
|
|||||||
}
|
}
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"type": "kotlinx.coroutines.CancelledContinuation"
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"type": "kotlinx.coroutines.CompletedExceptionally",
|
"type": "kotlinx.coroutines.CompletedExceptionally",
|
||||||
"fields": [
|
"fields": [
|
||||||
@ -1681,6 +1687,9 @@
|
|||||||
}
|
}
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"type": "kotlinx.coroutines.internal.LimitedDispatcher"
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"type": "kotlinx.coroutines.internal.LockFreeLinkedListNode",
|
"type": "kotlinx.coroutines.internal.LockFreeLinkedListNode",
|
||||||
"fields": [
|
"fields": [
|
||||||
@ -1714,6 +1723,9 @@
|
|||||||
}
|
}
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"type": "kotlinx.coroutines.internal.ThreadSafeHeap"
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"type": "kotlinx.coroutines.scheduling.CoroutineScheduler",
|
"type": "kotlinx.coroutines.scheduling.CoroutineScheduler",
|
||||||
"fields": [
|
"fields": [
|
||||||
@ -1728,6 +1740,12 @@
|
|||||||
}
|
}
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"type": "kotlinx.coroutines.scheduling.CoroutineScheduler$Worker"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "kotlinx.coroutines.scheduling.WorkQueue"
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"type": "libcore.io.Memory"
|
"type": "libcore.io.Memory"
|
||||||
},
|
},
|
||||||
@ -4898,6 +4916,15 @@
|
|||||||
}
|
}
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"type": "org.bouncycastle.jcajce.provider.kdf.PBKDF2$Mappings",
|
||||||
|
"methods": [
|
||||||
|
{
|
||||||
|
"name": "<init>",
|
||||||
|
"parameterTypes": []
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"type": "org.bouncycastle.jcajce.provider.kdf.SCRYPT$Mappings",
|
"type": "org.bouncycastle.jcajce.provider.kdf.SCRYPT$Mappings",
|
||||||
"methods": [
|
"methods": [
|
||||||
@ -10115,6 +10142,9 @@
|
|||||||
{
|
{
|
||||||
"glob": "META-INF/services/java.util.spi.ResourceBundleControlProvider"
|
"glob": "META-INF/services/java.util.spi.ResourceBundleControlProvider"
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"glob": "META-INF/services/kotlin.reflect.jvm.internal.impl.km.internal.extensions.MetadataExtensions"
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"glob": "META-INF/services/kotlin.reflect.jvm.internal.impl.resolve.ExternalOverridabilityCondition"
|
"glob": "META-INF/services/kotlin.reflect.jvm.internal.impl.resolve.ExternalOverridabilityCondition"
|
||||||
},
|
},
|
||||||
|
|||||||
@ -0,0 +1,114 @@
|
|||||||
|
package org.asamk.signal.json;
|
||||||
|
|
||||||
|
import org.asamk.signal.manager.api.RateLimitException;
|
||||||
|
import org.asamk.signal.manager.api.RecipientAddress;
|
||||||
|
import org.asamk.signal.manager.api.RecipientIdentifier;
|
||||||
|
import org.asamk.signal.manager.api.SendMessageResult;
|
||||||
|
import org.asamk.signal.manager.api.SendMessageResults;
|
||||||
|
import org.junit.jupiter.api.Test;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.UUID;
|
||||||
|
|
||||||
|
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||||
|
import static org.junit.jupiter.api.Assertions.assertNull;
|
||||||
|
|
||||||
|
class JsonSendMessageResultTest {
|
||||||
|
|
||||||
|
private static final RecipientAddress ADDRESS = new RecipientAddress(null, null, "+15551234567", null);
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void rateLimitFailureSurfacesRetryAfterSeconds() {
|
||||||
|
var result = new SendMessageResult(ADDRESS,
|
||||||
|
false,
|
||||||
|
false,
|
||||||
|
false,
|
||||||
|
false,
|
||||||
|
new RateLimitException(3600_000L),
|
||||||
|
null,
|
||||||
|
false);
|
||||||
|
|
||||||
|
var json = JsonSendMessageResult.from(result);
|
||||||
|
|
||||||
|
assertEquals(JsonSendMessageResult.Type.RATE_LIMIT_FAILURE, json.type());
|
||||||
|
assertEquals(3600L, json.retryAfterSeconds());
|
||||||
|
assertNull(json.token());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void rateLimitFailureWithoutRetryAfterLeavesFieldNull() {
|
||||||
|
var result = new SendMessageResult(ADDRESS,
|
||||||
|
false,
|
||||||
|
false,
|
||||||
|
false,
|
||||||
|
false,
|
||||||
|
new RateLimitException(null),
|
||||||
|
null,
|
||||||
|
false);
|
||||||
|
|
||||||
|
var json = JsonSendMessageResult.from(result);
|
||||||
|
|
||||||
|
assertEquals(JsonSendMessageResult.Type.RATE_LIMIT_FAILURE, json.type());
|
||||||
|
assertNull(json.retryAfterSeconds());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void successLeavesRetryAfterNull() {
|
||||||
|
var result = new SendMessageResult(ADDRESS, true, false, false, false, null, null, false);
|
||||||
|
|
||||||
|
var json = JsonSendMessageResult.from(result);
|
||||||
|
|
||||||
|
assertEquals(JsonSendMessageResult.Type.SUCCESS, json.type());
|
||||||
|
assertNull(json.retryAfterSeconds());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void aggregateReturnsLongestRetryAfter() {
|
||||||
|
var small = rateLimited("+15551234567", 60L);
|
||||||
|
var big = rateLimited("+15559876543", 3600L);
|
||||||
|
var unknown = rateLimited("+15550000000", null);
|
||||||
|
|
||||||
|
var aggregate = new SendMessageResults(1L,
|
||||||
|
Map.of(new RecipientIdentifier.Uuid(UUID.randomUUID()), List.of(small, big, unknown)));
|
||||||
|
|
||||||
|
assertEquals(3600L, aggregate.maxRateLimitRetryAfterMilliseconds());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void aggregateReturnsNullWhenNoRetryAfter() {
|
||||||
|
var aggregate = new SendMessageResults(1L,
|
||||||
|
Map.of(new RecipientIdentifier.Uuid(UUID.randomUUID()), List.of(rateLimited("+15551234567", null))));
|
||||||
|
|
||||||
|
assertNull(aggregate.maxRateLimitRetryAfterMilliseconds());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Regression for a bug where the aggregate helper could overlook the longest
|
||||||
|
* wait if only some recipients reported a value. Ensures the max is picked
|
||||||
|
* across any mix — which is what downstream captcha/rate-limit clients rely on.
|
||||||
|
*/
|
||||||
|
@Test
|
||||||
|
void aggregatePicksMaxEvenWhenSomeValuesAreNull() {
|
||||||
|
var withValue = rateLimited("+15551111111", 7200L);
|
||||||
|
var withoutValue = rateLimited("+15552222222", null);
|
||||||
|
var alsoWithValue = rateLimited("+15553333333", 120L);
|
||||||
|
|
||||||
|
var aggregate = new SendMessageResults(1L,
|
||||||
|
Map.of(new RecipientIdentifier.Uuid(UUID.randomUUID()),
|
||||||
|
List.of(withoutValue, withValue, alsoWithValue)));
|
||||||
|
|
||||||
|
assertEquals(7200L, aggregate.maxRateLimitRetryAfterMilliseconds());
|
||||||
|
}
|
||||||
|
|
||||||
|
private static SendMessageResult rateLimited(String number, Long retryAfterSeconds) {
|
||||||
|
return new SendMessageResult(new RecipientAddress(null, null, number, null),
|
||||||
|
false,
|
||||||
|
false,
|
||||||
|
false,
|
||||||
|
false,
|
||||||
|
new RateLimitException(retryAfterSeconds),
|
||||||
|
null,
|
||||||
|
false);
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -496,6 +496,14 @@ class SubscribeCallEventsTest {
|
|||||||
public void addClosedListener(Runnable l) {
|
public void addClosedListener(Runnable l) {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void addUnidentifiedKeepAlive(String token) {
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void removeUnidentifiedKeepAlive(String token) {
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public InputStream retrieveAttachment(String id) {
|
public InputStream retrieveAttachment(String id) {
|
||||||
return null;
|
return null;
|
||||||
@ -741,8 +749,8 @@ class SubscribeCallEventsTest {
|
|||||||
|
|
||||||
assertEquals(1, manager1.addCount.get(), "manager1 should have one listener");
|
assertEquals(1, manager1.addCount.get(), "manager1 should have one listener");
|
||||||
assertEquals(1, manager2.addCount.get(), "manager2 should have one listener");
|
assertEquals(1, manager2.addCount.get(), "manager2 should have one listener");
|
||||||
// Also registers an onManagerAdded handler for receive and one for call events
|
// Registers onManagerAdded handlers for receive, call events, and keep-alive
|
||||||
assertEquals(2, multi.addedHandlers.size(), "should register onManagerAdded handlers");
|
assertEquals(3, multi.addedHandlers.size(), "should register onManagerAdded handlers");
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user