Compare commits

..

89 Commits

Author SHA1 Message Date
jamesgeorge007
73a5f4657c refactor: cleanup CollectionsProperties component 2024-05-28 19:50:13 +05:30
jamesgeorge007
4ba53a8bf3 refactor: remove redundancy from provider API method signatures 2024-05-28 19:31:41 +05:30
jamesgeorge007
2374ceb808 refactor: update exportRESTCollections method signature
- Drop the `collections` parameter since the it is already available in the `PersonalWorkspaceProviderService` context.
- Make the above method return a left error of `NO_COLLECTIONS_TO_EXPORT` when the collections list is empty.
- Error handling updates.
2024-05-27 11:34:50 +05:30
jamesgeorge007
17169e1c46 chore: bump @hoppscotch/ui 2024-05-23 22:30:11 +05:30
jamesgeorge007
4c74d0f865 chore: cleanup 2024-05-23 14:20:42 +05:30
jamesgeorge007
8b930a6d3d fix: resolve edge cases about moving collections under its sibling
- Increase test coverage.
- Move store mock data under `__tests__/__mocks__`.
- Rephrase test descriptions.
2024-05-22 21:00:49 +05:30
jamesgeorge007
f4a37f19c9 fix: empty state primary action for root collections
Ensure child collections are created instead of the action resulting in new root collections.
2024-05-22 21:00:49 +05:30
jamesgeorge007
86b17e2bd3 test: add test suite for personal workspace provider service 2024-05-22 21:00:49 +05:30
jamesgeorge007
e0083aa70d fix: handle based updates post collection move to a sibling level collection below it 2024-05-22 21:00:49 +05:30
jamesgeorge007
25b0818016 refactor: update inherited properties for affected requests flow updates 2024-05-22 21:00:46 +05:30
jamesgeorge007
648cc8f5bd refactor: handle based updates for affected requests post collection deletion 2024-05-22 20:59:59 +05:30
jamesgeorge007
6032cbb17b refactor: handle based updates for affected requests post request deletion 2024-05-22 20:59:59 +05:30
jamesgeorge007
52bff8ee68 refactor: handle based updates post collection reorder 2024-05-22 20:59:59 +05:30
jamesgeorge007
e342e53db1 refactor: handle based updates post collection move 2024-05-22 20:59:58 +05:30
jamesgeorge007
141652ffb6 fix: affected request indices computation post request reorder 2024-05-22 20:59:38 +05:30
jamesgeorge007
bb57b2248c fix: affected request indices computation post request move 2024-05-22 20:59:21 +05:30
jamesgeorge007
5d8da5fe49 chore: resolve type errors 2024-05-22 20:59:21 +05:30
Andrew Bastin
c8f0142b16 refactor: move more things to handles instead of handleref 2024-05-22 20:59:20 +05:30
jamesgeorge007
2f2273ee2c refactor: move to inert handles 2024-05-22 20:58:28 +05:30
jamesgeorge007
b239b6b4a6 refactor: handle updates post move request action
- Filter out duplicate issued handle entries.
- Move from `getAffectedIndexes` helper function to a custom implementation for updating affected request indices.
2024-05-22 20:57:48 +05:30
jamesgeorge007
bbac317b71 refactor: move to handle based updates with request move action 2024-05-22 20:57:48 +05:30
jamesgeorge007
412daa4d17 refactor: tab saveContext resolution post collection remove action 2024-05-22 20:57:48 +05:30
jamesgeorge007
0abdc63f0e refactor: better tab dirty check
Mark the tab (saved request under a collection) as not dirty if the request contents are reset to the value since previous save.
2024-05-22 20:57:47 +05:30
jamesgeorge007
9e8112a4e5 fix: make close all tabs action account for tabs with invalid request handles 2024-05-22 20:56:47 +05:30
jamesgeorge007
5aa57fce3f refactor: add save context resolution logic post request deletion 2024-05-22 20:56:47 +05:30
jamesgeorge007
8b65090dfb refactor: persist only request handles under tab saveContext at runtime
Remove provider, workspace and request IDs.
2024-05-22 20:56:47 +05:30
jamesgeorge007
7ca94a99b7 refactor: move tab saveContext resolution associated with actions on collections to be based on request handles 2024-05-22 20:56:46 +05:30
jamesgeorge007
fe3adeeb17 refactor: consider request handles with tab saveContext resolution for collection move/reorder actions 2024-05-22 20:56:17 +05:30
jamesgeorge007
3a195711a4 refactor: update data under request handles during tab save context resolution 2024-05-22 20:56:17 +05:30
jamesgeorge007
6cde6200ae refactor: signify updates via handle reference mutation post request move action 2024-05-22 20:56:17 +05:30
jamesgeorge007
e5e1260632 fix: ensure request name updates reflect immediately on the tabs 2024-05-22 20:56:17 +05:30
jamesgeorge007
90c9f2a9b1 fix: make writable handle operate on refs within the createRESTRequest method
Wrap the request handle data in a `ref` and make the writable handle operate over it ensuring reactive updates are received.
2024-05-22 20:56:17 +05:30
jamesgeorge007
db9ba17529 refactor: convey updates via handle mutation for update request action 2024-05-22 20:56:17 +05:30
jamesgeorge007
197d253e8b refactor: keep tab dirty status logic at the page level 2024-05-22 20:56:17 +05:30
jamesgeorge007
cd92dfec47 refactor: introduce writable handles to signify updates to handle references
A special list of writable handles is compiled in a list while issuing handles (request/collection creation, etc). Instead of manually computing the tab and toggling the dirty state, the writable handle is updated (changing the type to invalid on request deletion) and the tab with the request open can infer it via the update reflected in the request handle under the tab save context (reactive update trigger).
2024-05-22 20:53:49 +05:30
jamesgeorge007
8467417e7a refactor: persist request handles under tab saveContext
Only the IDs (workspace, provider & request IDs) to restore the handle are stored under `localStorage` and the handle is restored back at runtime.
2024-05-22 20:53:15 +05:30
jamesgeorge007
f6067f14aa fix: prevent infinite spinner state while expanding tree nodes 2024-05-22 20:52:57 +05:30
jamesgeorge007
3fd85df84b refactor: view implementation to retrieve collections for exporting 2024-05-22 20:52:57 +05:30
jamesgeorge007
01573cc51c chore: keep existing implementation for save context resolution 2024-05-22 20:52:57 +05:30
jamesgeorge007
b19486ea03 refactor: update provider method signatures + cleanup 2024-05-22 20:52:57 +05:30
jamesgeorge007
a729dfcacb fix: ensure tree nodes are not computed for requests 2024-05-22 20:52:57 +05:30
jamesgeorge007
62612e6c51 refactor: remove unnecessary safeguards + cleanup 2024-05-22 20:52:57 +05:30
jamesgeorge007
f87a4c81d8 refactor: leverage helpers 2024-05-22 20:52:57 +05:30
jamesgeorge007
116f2fd279 refactor: update provider method signatures 2024-05-22 20:52:57 +05:30
jamesgeorge007
7e2deaac5b fix: duplicate collection in search results
Ensure the entire collection tree is rendered if the search query matches a collection name.
2024-05-22 20:52:57 +05:30
jamesgeorge007
240b131e06 feat: support search at n level depth 2024-05-22 20:52:57 +05:30
jamesgeorge007
5b3986a53f fix: ensure the collection tree for search immediately reflects actions performed over it 2024-05-22 20:52:57 +05:30
jamesgeorge007
84fc31e8a9 refactor: port collection tree empty states 2024-05-22 20:52:56 +05:30
jamesgeorge007
c0978c3b20 refactor: eliminate parentCollectionID field from RESTCollectionViewRequest type
Collection ID serves the purpose.
2024-05-22 20:52:56 +05:30
jamesgeorge007
d70d5bdb16 refactor: eliminate collectionID from tab saveContext
Collection ID can be inferred from request ID by removing last index from the path.
2024-05-22 20:52:56 +05:30
jamesgeorge007
c30ee5becc refactor: session based search results view implementation 2024-05-22 20:50:32 +05:30
jamesgeorge007
5a64cdb7bc fix: update save context for affected requests with collection move/reorder 2024-05-22 20:50:32 +05:30
jamesgeorge007
89f2479845 refactor: integrate REST search collection adapter 2024-05-22 20:50:32 +05:30
jamesgeorge007
46654853f0 refactor: add new tree adapter corresponding to search 2024-05-22 20:50:32 +05:30
jamesgeorge007
af7e6b70cd refactor: view based implementation for search in personal workspace 2024-05-22 20:50:32 +05:30
jamesgeorge007
7c52c6b79d fix: associate requests under tabs while reordering collections 2024-05-22 20:50:32 +05:30
jamesgeorge007
fe01322bf7 refactor: integrate provider API methods for collection move/reorder 2024-05-22 20:50:32 +05:30
jamesgeorge007
0a0f441da1 refactor: unify markup 2024-05-22 20:50:32 +05:30
jamesgeorge007
d0c7c4a245 refactor: provider method definitions for collection reorder/move 2024-05-22 20:50:32 +05:30
jamesgeorge007
076006c4a6 refactor: port collection move/reorder 2024-05-22 20:50:32 +05:30
jamesgeorge007
6ed9c09f06 refactor: port import/export functionality 2024-05-22 20:50:31 +05:30
jamesgeorge007
8483339005 feat: add keypress actions 2024-05-22 20:49:49 +05:30
jamesgeorge007
cd23bb63c1 refactor: remove fields associated with pagination
Fix lint errors
2024-05-22 20:49:13 +05:30
James George
f4ea999d2d refactor: remove unnecessary imports and local state variable 2024-05-22 20:49:13 +05:30
jamesgeorge007
c43e4fcefd fix: open request straightaway after creating via save-as 2024-05-22 20:49:13 +05:30
jamesgeorge007
316dc8f759 refactor: persist IDs under tab save context 2024-05-22 20:49:12 +05:30
jamesgeorge007
89f7c2ce5e refactor: port share requests 2024-05-22 20:41:24 +05:30
jamesgeorge007
0d00826019 fix: ensure removing collection level headers persists 2024-05-22 20:41:24 +05:30
jamesgeorge007
00285df348 refactor: remove side effects from computed properties 2024-05-22 20:41:24 +05:30
jamesgeorge007
b821f452cf fix: ensure the reference is not kept while overwriting requests 2024-05-22 20:41:24 +05:30
jamesgeorge007
faa0bf7714 fix: updates to collection level authorization and headers reflect at the request level straightaway 2024-05-22 20:41:23 +05:30
jamesgeorge007
3a176f6620 fix: invalidate requests opened under tabs on deleting parent collection 2024-05-22 20:33:04 +05:30
jamesgeorge007
7549e456c8 fix: specify correct request index with update action 2024-05-22 20:33:04 +05:30
jamesgeorge007
68795a5017 refactor: port collection tree rendered in the save request modal to the new implementation 2024-05-22 20:33:03 +05:30
jamesgeorge007
b0c72fd295 feat: indicate request opened in the tab from the collection tree 2024-05-22 20:32:18 +05:30
jamesgeorge007
63eca80ff6 fix: prevent the need for an explicit save while editing request name 2024-05-22 20:32:18 +05:30
jamesgeorge007
30b6a67505 fix: prevent duplicate request creation and invalidate tabs with request deletion 2024-05-22 20:32:18 +05:30
jamesgeorge007
97899ec023 chore: cleanup 2024-05-22 20:32:18 +05:30
jamesgeorge007
2c47a63ca0 refactor: update provider method signature 2024-05-22 20:32:18 +05:30
jamesgeorge007
a0e373a4f3 refactor: persist request handle under tab saveContext
Bump vue version.
2024-05-22 20:32:16 +05:30
jamesgeorge007
392b2fc48d refactor: updates based on the provider methods signature changes 2024-05-22 20:30:55 +05:30
jamesgeorge007
c1a8a871d2 refactor: save request handle in tabs and remove tabs related logic from personal provider definition 2024-05-22 20:28:56 +05:30
jamesgeorge007
1abbdb0fe0 refactor: consistent return formats 2024-05-22 20:21:43 +05:30
jamesgeorge007
f0f504d10e refactor: unify edit collection API methods and ensure consistent naming convention 2024-05-22 20:21:42 +05:30
jamesgeorge007
f0dab55c99 refactor: prevent storing entire collection data in the respective handle 2024-05-22 20:21:15 +05:30
jamesgeorge007
d6a8e60239 refactor: finalize API methods 2024-05-22 20:21:14 +05:30
jamesgeorge007
89bcc58de6 refactor: compile data in handles
Introduce a handle for requests.
2024-05-22 20:16:54 +05:30
jamesgeorge007
ab7df212c2 refactor: iterations 2024-05-22 20:11:39 +05:30
jamesgeorge007
29e25b0ead refactor: initial iterations
Co-authored-by: Andrew Bastin <andrewbastin.k@gmail.com>
2024-05-22 20:10:50 +05:30
745 changed files with 31361 additions and 68028 deletions

View File

@@ -6,17 +6,9 @@ DATABASE_URL=postgresql://postgres:testpass@hoppscotch-db:5432/hoppscotch
JWT_SECRET="secret1233"
TOKEN_SALT_COMPLEXITY=10
MAGIC_LINK_TOKEN_VALIDITY= 3
# Default validity is 7 days (604800000 ms) in ms
REFRESH_TOKEN_VALIDITY="604800000"
# Default validity is 1 day (86400000 ms) in ms
ACCESS_TOKEN_VALIDITY="86400000"
REFRESH_TOKEN_VALIDITY="604800000" # Default validity is 7 days (604800000 ms) in ms
ACCESS_TOKEN_VALIDITY="86400000" # Default validity is 1 day (86400000 ms) in ms
SESSION_SECRET='add some secret here'
# Reccomended to be true, set to false if you are using http
# Note: Some auth providers may not support http requests
ALLOW_SECURE_COOKIES=true
# Sensitive Data Encryption Key while storing in Database (32 character)
DATA_ENCRYPTION_KEY="data encryption key with 32 char"
# Hoppscotch App Domain Config
REDIRECT_URL="http://localhost:3000"
@@ -43,20 +35,9 @@ MICROSOFT_SCOPE="user.read"
MICROSOFT_TENANT="common"
# Mailer config
MAILER_SMTP_ENABLE="true"
MAILER_USE_CUSTOM_CONFIGS="false"
MAILER_SMTP_URL="smtps://user@domain.com:pass@smtp.domain.com"
MAILER_ADDRESS_FROM='"From Name Here" <from@example.com>'
MAILER_SMTP_URL="smtps://user@domain.com:pass@smtp.domain.com" # used if custom mailer configs is false
# The following are used if custom mailer configs is true
MAILER_SMTP_HOST="smtp.domain.com"
MAILER_SMTP_PORT="587"
MAILER_SMTP_SECURE="true"
MAILER_SMTP_USER="user@domain.com"
MAILER_SMTP_PASSWORD="pass"
MAILER_TLS_REJECT_UNAUTHORIZED="true"
# Rate Limit Config
RATE_LIMIT_TTL=60 # In seconds
RATE_LIMIT_MAX=100 # Max requests per IP
@@ -66,7 +47,6 @@ RATE_LIMIT_MAX=100 # Max requests per IP
# Base URLs
VITE_BACKEND_LOGIN_API_URL=http://localhost:5444
VITE_BASE_URL=http://localhost:3000
VITE_SHORTCODE_BASE_URL=http://localhost:3000
VITE_ADMIN_URL=http://localhost:3100

View File

@@ -7,15 +7,20 @@ Please make sure that the pull request is limited to one type (docs, feature, et
<!-- If this pull request closes an issue, please mention the issue number below -->
Closes # <!-- Issue # here -->
<!-- Add an introduction into what this PR tries to solve in a couple of sentences -->
### What's changed
<!-- Describe point by point the different things you have changed in this PR -->
### Description
<!-- Add a brief description of the pull request -->
<!-- You can also choose to add a list of changes and if they have been completed or not by using the markdown to-do list syntax
- [ ] Not Completed
- [x] Completed
-->
### Notes to reviewers
<!-- Any information you feel the reviewer should know about when reviewing your PR -->
### Checks
<!-- Make sure your pull request passes the CI checks and do check the following fields as needed - -->
- [ ] My pull request adheres to the code style of this project
- [ ] My code requires changes to the documentation
- [ ] I have updated the documentation as required
- [ ] All the tests have passed
### Additional Information
<!-- Any additional information like breaking changes, dependencies added, screenshots, comparisons between new and old behaviour, etc. -->

View File

@@ -1,249 +0,0 @@
on:
workflow_dispatch:
inputs:
version:
description: Tag of the version to build
required: true
env:
CARGO_TERM_COLOR: always
jobs:
build:
strategy:
fail-fast: false
matrix:
platform: [macos-latest, ubuntu-22.04, windows-latest]
runs-on: ${{ matrix.platform }}
defaults:
run:
shell: bash
steps:
- name: Checkout hoppscotch/hoppscotch
uses: actions/checkout@v3
with:
repository: hoppscotch/hoppscotch
ref: main
token: ${{ secrets.CHECKOUT_GITHUB_TOKEN }}
- name: Setup Node.js
uses: actions/setup-node@v3
with:
node-version: 20
- name: Setup pnpm
uses: pnpm/action-setup@v2
with:
version: 9
- name: Install Rust
uses: actions-rs/toolchain@v1
with:
toolchain: stable
override: true
- name: Install Rust targets (Mac)
if: matrix.platform == 'macos-latest'
run: |
rustup target add aarch64-apple-darwin
rustup target add x86_64-apple-darwin
- name: Install additional tools (Linux)
if: matrix.platform == 'ubuntu-22.04'
run: |
# Install Tauri CLI (binary)
curl -LO "https://github.com/tauri-apps/tauri/releases/download/tauri-cli-v2.0.1/cargo-tauri-x86_64-unknown-linux-gnu.tgz"
tar -xzf cargo-tauri-x86_64-unknown-linux-gnu.tgz
chmod +x cargo-tauri
sudo mv cargo-tauri /usr/local/bin/tauri
# Install Trunk (binary)
curl -LO "https://github.com/thedodd/trunk/releases/download/v0.17.5/trunk-x86_64-unknown-linux-gnu.tar.gz"
tar -xzf trunk-x86_64-unknown-linux-gnu.tar.gz
chmod +x trunk
sudo mv trunk /usr/local/bin/
- name: Install additional tools (Mac)
if: matrix.platform == 'macos-latest'
run: |
# Install Tauri CLI (binary)
mkdir __dist/
cd __dist/
curl -LO "https://github.com/tauri-apps/tauri/releases/download/tauri-cli-v2.0.1/cargo-tauri-aarch64-apple-darwin.zip"
unzip cargo-tauri-aarch64-apple-darwin.zip
chmod +x cargo-tauri
sudo mv cargo-tauri /usr/local/bin/tauri
- name: Install system dependencies (Ubuntu only)
if: matrix.platform == 'ubuntu-22.04'
run: |
sudo apt-get update
sudo apt-get install -y libwebkit2gtk-4.1-dev \
build-essential \
curl \
wget \
file \
libxdo-dev \
libssl-dev \
libayatana-appindicator3-dev \
librsvg2-dev
- name: Setting up Windows Environment and injecting before bundle command (Windows only)
if: matrix.platform == 'windows-latest'
shell: bash
env:
WINDOWS_SIGN_COMMAND: trusted-signing-cli -e ${{ secrets.AZURE_ENDPOINT }} -a ${{ secrets.AZURE_CODE_SIGNING_NAME }} -c ${{ secrets.AZURE_CERT_PROFILE_NAME }} %1
run: |
cd packages/hoppscotch-agent
# Inject signing command into main conf.
cat './src-tauri/tauri.conf.json' | jq '.bundle .windows += { "signCommand": env.WINDOWS_SIGN_COMMAND}' > './src-tauri/temp.json' && mv './src-tauri/temp.json' './src-tauri/tauri.conf.json'
# Inject signing command into portable conf.
cat './src-tauri/tauri.portable.conf.json' | jq '.bundle .windows += { "signCommand": env.WINDOWS_SIGN_COMMAND}' > './src-tauri/temp_portable.json' && mv './src-tauri/temp_portable.json' './src-tauri/tauri.portable.conf.json'
cargo install trusted-signing-cli@0.3.0
- name: Set platform-specific variables
run: |
if [ "${{ matrix.platform }}" = "ubuntu-22.04" ]; then
echo "target_arch=$(rustc -Vv | grep host | awk '{print $2}')" >> $GITHUB_ENV
echo "target_ext=" >> $GITHUB_ENV
echo "target_os_name=linux" >> $GITHUB_ENV
elif [ "${{ matrix.platform }}" = "windows-latest" ]; then
echo "target_arch=x86_64-pc-windows-msvc" >> $GITHUB_ENV
echo "target_ext=.exe" >> $GITHUB_ENV
echo "target_os_name=win" >> $GITHUB_ENV
elif [ "${{ matrix.platform }}" = "macos-latest" ]; then
echo "target_os_name=mac" >> $GITHUB_ENV
fi
- name: Setup macOS code signing
if: matrix.platform == 'macos-latest'
env:
APPLE_CERTIFICATE: ${{ secrets.APPLE_CERTIFICATE }}
APPLE_CERTIFICATE_PASSWORD: ${{ secrets.APPLE_CERTIFICATE_PASSWORD }}
APPLE_SIGNING_IDENTITY: ${{ secrets.APPLE_SIGNING_IDENTITY }}
KEYCHAIN_PASSWORD: ${{ secrets.KEYCHAIN_PASSWORD }}
run: |
echo $APPLE_CERTIFICATE | base64 --decode > certificate.p12
security create-keychain -p $KEYCHAIN_PASSWORD build.keychain
security default-keychain -s build.keychain
security unlock-keychain -p $KEYCHAIN_PASSWORD build.keychain
security import certificate.p12 -k build.keychain -P $APPLE_CERTIFICATE_PASSWORD -T /usr/bin/codesign
security set-key-partition-list -S apple-tool:,apple:,codesign: -s -k $KEYCHAIN_PASSWORD build.keychain
- name: Cache Rust dependencies
uses: actions/cache@v3
with:
path: |
~/.cargo/registry
~/.cargo/git
target
key: ${{ runner.os }}-cargo-${{ hashFiles('**/Cargo.lock') }}
- name: Install dependencies
shell: bash
run: |
cd packages/hoppscotch-agent
pnpm install --filter hoppscotch-agent
- name: Build Tauri app (Linux)
if: matrix.platform == 'ubuntu-22.04'
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
TAURI_SIGNING_PRIVATE_KEY: ${{ secrets.AGENT_TAURI_SIGNING_PRIVATE_KEY }}
TAURI_SIGNING_PRIVATE_KEY_PASSWORD: ${{ secrets.AGENT_TAURI_SIGNING_PASSWORD }}
run: |
cd packages/hoppscotch-agent
pnpm tauri build --verbose -b deb -b appimage -b updater
- name: Build Tauri app (Mac)
if: matrix.platform == 'macos-latest'
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
TAURI_SIGNING_PRIVATE_KEY: ${{ secrets.AGENT_TAURI_SIGNING_PRIVATE_KEY }}
TAURI_SIGNING_PRIVATE_KEY_PASSWORD: ${{ secrets.AGENT_TAURI_SIGNING_PASSWORD }}
APPLE_ID: ${{ secrets.APPLE_ID }}
APPLE_PASSWORD: ${{ secrets.APPLE_PASSWORD }}
APPLE_TEAM_ID: ${{ secrets.APPLE_TEAM_ID }}
APPLE_SIGNING_IDENTITY: ${{ secrets.APPLE_SIGNING_IDENTITY }}
run: |
cd packages/hoppscotch-agent
pnpm tauri build --verbose --target x86_64-apple-darwin
pnpm tauri build --verbose --target aarch64-apple-darwin
- name: Build Tauri app (Windows)
if: matrix.platform == 'windows-latest'
shell: powershell
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
TAURI_SIGNING_PRIVATE_KEY: ${{ secrets.AGENT_TAURI_SIGNING_PRIVATE_KEY }}
TAURI_SIGNING_PRIVATE_KEY_PASSWORD: ${{ secrets.AGENT_TAURI_SIGNING_PASSWORD }}
AZURE_TENANT_ID: ${{ secrets.AZURE_TENANT_ID }}
AZURE_CLIENT_ID: ${{ secrets.AZURE_CLIENT_ID }}
AZURE_CLIENT_SECRET: ${{ secrets.AZURE_CLIENT_SECRET }}
run: |
cd packages/hoppscotch-agent
# Build the portable version first and move it.
# This way the next build will regenerate `hoppscotch-agent.exe`.
pnpm tauri build --verbose --config src-tauri/tauri.portable.conf.json -- --no-default-features --features portable
Rename-Item -Path "src-tauri/target/release/hoppscotch-agent.exe" -NewName "hoppscotch-agent-portable.exe"
# Build the installer version.
pnpm tauri build --verbose -b msi -b updater
- name: Zip portable executable (Windows)
if: matrix.platform == 'windows-latest'
shell: powershell
run: |
Compress-Archive -Path "packages/hoppscotch-agent/src-tauri/target/release/hoppscotch-agent-portable.exe" -DestinationPath "packages/hoppscotch-agent/src-tauri/target/release/Hoppscotch_Agent_win_x64_portable.zip"
- name: Prepare artifacts
shell: bash
run: |
mkdir artifacts
mkdir artifacts/sigs
if [ "${{ matrix.platform }}" = "ubuntu-22.04" ]; then
mv packages/hoppscotch-agent/src-tauri/target/release/bundle/appimage/*.AppImage artifacts/Hoppscotch_Agent_linux_x64.AppImage
mv packages/hoppscotch-agent/src-tauri/target/release/bundle/appimage/*.AppImage.sig artifacts/sigs/Hoppscotch_Agent_linux_x64.AppImage.sig
mv packages/hoppscotch-agent/src-tauri/target/release/bundle/deb/*.deb artifacts/Hoppscotch_Agent_linux_x64.deb
elif [ "${{ matrix.platform }}" = "macos-latest" ]; then
mv packages/hoppscotch-agent/src-tauri/target/x86_64-apple-darwin/release/bundle/dmg/*_x64.dmg artifacts/Hoppscotch_Agent_mac_x64.dmg
mv packages/hoppscotch-agent/src-tauri/target/x86_64-apple-darwin/release/bundle/macos/*.app.tar.gz artifacts/Hoppscotch_Agent_mac_update_x64.tar.gz
mv packages/hoppscotch-agent/src-tauri/target/x86_64-apple-darwin/release/bundle/macos/*.app.tar.gz.sig artifacts/sigs/Hoppscotch_Agent_mac_update_x64.tar.gz.sig
mv packages/hoppscotch-agent/src-tauri/target/aarch64-apple-darwin/release/bundle/dmg/*_aarch64.dmg artifacts/Hoppscotch_Agent_mac_aarch64.dmg
mv packages/hoppscotch-agent/src-tauri/target/aarch64-apple-darwin/release/bundle/macos/*.app.tar.gz artifacts/Hoppscotch_Agent_mac_update_aarch64.tar.gz
mv packages/hoppscotch-agent/src-tauri/target/aarch64-apple-darwin/release/bundle/macos/*.app.tar.gz.sig artifacts/sigs/Hoppscotch_Agent_mac_update_aarch64.tar.gz.sig
elif [ "${{ matrix.platform }}" = "windows-latest" ]; then
mv packages/hoppscotch-agent/src-tauri/target/release/bundle/msi/*_x64_en-US.msi artifacts/Hoppscotch_Agent_win_x64.msi
mv packages/hoppscotch-agent/src-tauri/target/release/bundle/msi/*_x64_en-US.msi.sig artifacts/sigs/Hoppscotch_Agent_win_x64.msi.sig
mv packages/hoppscotch-agent/src-tauri/target/release/Hoppscotch_Agent_win_x64_portable.zip artifacts/Hoppscotch_Agent_win_x64_portable.zip
fi
- name: Generate checksums (Linux)
if: matrix.platform == 'ubuntu-22.04'
run: |
cd artifacts
mkdir shas
for file in *; do
if [ -f "$file" ]; then
sha256sum "$file" > "shas/${file}.sha256"
fi
done
- name: Generate checksums (Mac)
if: matrix.platform == 'macos-latest'
run: |
cd artifacts
mkdir shas
for file in *; do
if [ -f "$file" ]; then
shasum -a 256 "$file" > "shas/${file}.sha256"
fi
done
- name: Upload artifacts
uses: actions/upload-artifact@v4
with:
name: Hoppscotch_Agent-${{ matrix.platform }}
path: artifacts/*

View File

@@ -33,7 +33,7 @@ jobs:
steps:
- name: Checkout
uses: actions/checkout@v4
uses: actions/checkout@v3
# Initializes the CodeQL tools for scanning.
- name: Initialize CodeQL

View File

@@ -10,7 +10,7 @@ jobs:
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v4
uses: actions/checkout@v3
- name: Setup environment
run: cp .env.example .env

View File

@@ -2,9 +2,9 @@ name: Node.js CI
on:
push:
branches: [main, next, patch]
branches: [main, staging, "release/**"]
pull_request:
branches: [main, next, patch]
branches: [main, staging, "release/**"]
jobs:
test:

View File

@@ -14,7 +14,7 @@ jobs:
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v4
uses: actions/checkout@v3
- name: Setup environment
run: mv .env.example .env
@@ -26,7 +26,7 @@ jobs:
run_install: true
- name: Setup node
uses: actions/setup-node@v4
uses: actions/setup-node@v3
with:
node-version: ${{ matrix.node }}
cache: pnpm

1
.gitignore vendored
View File

@@ -19,7 +19,6 @@ pids
*.pid
*.seed
*.pid.lock
*.env
# Directory for instrumented libs generated by jscoverage/JSCover
lib-cov

View File

@@ -1 +1,4 @@
#!/bin/sh
. "$(dirname "$0")/_/husky.sh"
npx --no-install commitlint --edit ""

View File

@@ -1 +1,4 @@
npm run pre-commit
#!/bin/sh
. "$(dirname "$0")/_/husky.sh"
npm run pre-commit

View File

@@ -1,21 +1,30 @@
# CODEOWNERS is prioritized from bottom to top
# If none of the below matched
* @AndrewBastin @liyasthomas
# Packages
/packages/codemirror-lang-graphql/ @AndrewBastin
/packages/hoppscotch-cli/ @jamesgeorge007
/packages/hoppscotch-cli/ @AndrewBastin
/packages/hoppscotch-common/ @amk-dev @AndrewBastin
/packages/hoppscotch-data/ @AndrewBastin
/packages/hoppscotch-js-sandbox/ @jamesgeorge007
/packages/hoppscotch-selfhost-web/ @jamesgeorge007
/packages/hoppscotch-selfhost-desktop/ @AndrewBastin
/packages/hoppscotch-js-sandbox/ @AndrewBastin
/packages/hoppscotch-ui/ @anwarulislam
/packages/hoppscotch-web/ @amk-dev
/packages/hoppscotch-selfhost-web/ @amk-dev
/packages/hoppscotch-sh-admin/ @JoelJacobStephen
/packages/hoppscotch-backend/ @balub
/packages/hoppscotch-backend/ @ankitsridhar16 @balub
# READMEs and other documentation files
*.md @liyasthomas
# Sections within Hoppscotch Common
/packages/hoppscotch-common/src/components @anwarulislam
/packages/hoppscotch-common/src/components/collections @nivedin @amk-dev
/packages/hoppscotch-common/src/components/environments @nivedin @amk-dev
/packages/hoppscotch-common/src/composables @amk-dev
/packages/hoppscotch-common/src/modules @AndrewBastin @amk-dev
/packages/hoppscotch-common/src/pages @AndrewBastin @amk-dev
/packages/hoppscotch-common/src/newstore @AndrewBastin @amk-dev
# Self Host deployment related files
*.Dockerfile @balub
docker-compose.yml @balub
docker-compose.deploy.yml @balub
*.Caddyfile @balub
.dockerignore @balub
README.md @liyasthomas
# The lockfile has no owner
pnpm-lock.yaml

View File

@@ -11,4 +11,7 @@ Please note we have a code of conduct, please follow it in all your interactions
build.
2. Update the README.md with details of changes to the interface, this includes new environment
variables, exposed ports, useful file locations and container parameters.
3. Make sure you do not expose environment variables or other sensitive information in your PR.
3. Increase the version numbers in any examples files and the README.md to the new version that this
Pull Request would represent. The versioning scheme we use is [SemVer](https://semver.org).
4. You may merge the Pull Request once you have the sign-off of two other developers, or if you
do not have permission to do that, you may request the second reviewer merge it for you.

View File

@@ -4,36 +4,19 @@ This document outlines security procedures and general policies for the Hoppscot
- [Security Policy](#security-policy)
- [Reporting a security vulnerability](#reporting-a-security-vulnerability)
- [What is not a valid vulnerability](#what-is-not-a-valid-vulnerability)
- [Incident response process](#incident-response-process)
## Reporting a security vulnerability
We use [Github Security Advisories](https://github.com/hoppscotch/hoppscotch/security/advisories) to manage vulnerability reports and collaboration.
Someone from the Hoppscotch team shall report to you within 48 hours of the disclosure of the vulnerability in GHSA. If no response was received, please reach out to
Hoppscotch Support at support@hoppscotch.io along with the GHSA advisory link.
Report security vulnerabilities by emailing the Hoppscotch Support team at support@hoppscotch.io.
> NOTE: Since we have multiple open source components, Advisories may move into the relevant repo (for example, an XSS in a UI component might be part of [`@hoppscotch/ui`](https://github.com/hoppscotch/ui)).
> If in doubt, open your report in `hoppscotch/hoppscotch` GHSA.
The primary security point of contact from Hoppscotch Support team will acknowledge your email within 48 hours, and will send a more detailed response within 48 hours indicating the next steps in handling your report. After the initial reply to your report, the security team will endeavor to keep you informed of the progress towards a fix and full announcement, and may ask for additional information or guidance.
**Do not create a GitHub issue ticket to report a security vulnerability!**
**Do not create a GitHub issue ticket to report a security vulnerability.**
The Hoppscotch team takes all security vulnerability reports in Hoppscotch seriously. We appreciate your efforts and responsible disclosure and will make every effort to acknowledge your contributions.
The Hoppscotch team and community take all security vulnerability reports in Hoppscotch seriously. Thank you for improving the security of Hoppscotch. We appreciate your efforts and responsible disclosure and will make every effort to acknowledge your contributions.
## What is not a valid vulnerability
We receive many reports about different sections of the Hoppscotch platform. Hence, we have a fine line we have drawn defining what is considered valid vulnerability.
Please refrain from opening an advisory if it describes the following:
- A vulnerability in a dependency of Hoppscotch (unless you have practical attack with it on the Hoppscotch codebase)
- Reports of vulnerabilities related to old runtimes (like NodeJS) or container images used by the codebase
- Vulnerabilities present when using Hoppscotch in anything other than the defined minimum requirements that Hoppscotch supports.
Hoppscotch Team ensures security support for:
- Modern Browsers (Chrome/Firefox/Safari/Edge) with versions up to 1 year old.
- Windows versions on or above Windows 10 on Intel and ARM.
- macOS versions dating back up to 2 years on Intel and Apple Silicon.
- Popular Linux distributions with up-to-date packages with preference to x86/64 CPUs.
- Docker/OCI Runtimes (preference to Docker and Podman) dating back up to 1 year.
Report security bugs in third-party modules to the person or team maintaining the module.
## Incident response process

View File

@@ -1,8 +1,3 @@
{
admin off
persist_config off
}
:3000 {
try_files {path} /
root * /site/selfhost-web
@@ -18,3 +13,7 @@
:3170 {
reverse_proxy localhost:8080
}
:80 {
respond 404
}

View File

@@ -1,9 +1,16 @@
{
admin off
persist_config off
:3000 {
respond 404
}
:{$HOPP_AIO_ALTERNATE_PORT:80} {
:3100 {
respond 404
}
:3170 {
reverse_proxy localhost:8080
}
:80 {
# Serve the `selfhost-web` SPA by default
root * /site/selfhost-web
file_server

View File

@@ -51,7 +51,7 @@ fs.rmSync("build.env")
const caddyFileName = process.env.ENABLE_SUBPATH_BASED_ACCESS === 'true' ? 'aio-subpath-access.Caddyfile' : 'aio-multiport-setup.Caddyfile'
const caddyProcess = runChildProcessWithPrefix("caddy", ["run", "--config", `/etc/caddy/${caddyFileName}`, "--adapter", "caddyfile"], "App/Admin Dashboard Caddy")
const backendProcess = runChildProcessWithPrefix("node", ["/dist/backend/dist/main.js"], "Backend Server")
const backendProcess = runChildProcessWithPrefix("pnpm", ["run", "start:prod"], "Backend Server")
caddyProcess.on("exit", (code) => {
console.log(`Exiting process because Caddy Server exited with code ${code}`)

View File

@@ -1,6 +1,8 @@
# THIS IS NOT TO BE USED FOR PERSONAL DEPLOYMENTS!
# Internal Docker Compose Image used for internal testing deployments
version: "3.7"
services:
hoppscotch-db:
image: postgres:15

View File

@@ -1,6 +1,7 @@
# To make it easier to self-host, we have a preset docker compose config that also
# has a container with a Postgres instance running.
# You can tweak around this file to match your instances
version: "3.7"
services:
# This service runs the backend app in the port 3170
@@ -99,7 +100,7 @@ services:
test:
[
"CMD-SHELL",
"sh -c 'pg_isready -U $${POSTGRES_USER} -d $${POSTGRES_DB}'",
"sh -c 'pg_isready -U $${POSTGRES_USER} -d $${POSTGRES_DB}'"
]
interval: 5s
timeout: 5s

View File

@@ -1,4 +1,4 @@
#!/bin/sh
#!/bin/bash
curlCheck() {
if ! curl -s --head "$1" | head -n 1 | grep -q "HTTP/1.[01] [23].."; then

View File

@@ -7,7 +7,7 @@
"license": "MIT",
"scripts": {
"preinstall": "npx only-allow pnpm",
"prepare": "husky",
"prepare": "husky install",
"dev": "pnpm -r do-dev",
"gen-gql": "cross-env GQL_SCHEMA_EMIT_LOCATION='../../../gql-gen/backend-schema.gql' pnpm -r generate-gql-sdl",
"generate": "pnpm -r do-build-prod",
@@ -23,31 +23,21 @@
"./packages/*"
],
"devDependencies": {
"@commitlint/cli": "19.5.0",
"@commitlint/config-conventional": "19.5.0",
"@hoppscotch/ui": "0.2.2",
"@types/node": "22.7.6",
"@commitlint/cli": "16.3.0",
"@commitlint/config-conventional": "16.2.4",
"@hoppscotch/ui": "0.1.0",
"@types/node": "17.0.27",
"cross-env": "7.0.3",
"http-server": "14.1.1",
"husky": "9.1.6",
"lint-staged": "15.2.10"
"husky": "7.0.4",
"lint-staged": "12.4.0"
},
"pnpm": {
"overrides": {
"cookie": "0.7.2",
"vue": "3.5.12",
"@nestjs-modules/mailer>mjml": "5.0.0-alpha.4",
"subscriptions-transport-ws>ws": "7.5.10",
"braces": "3.0.3",
"send": "0.19.0",
"pug": "3.0.3",
"body-parser": "1.20.3",
"path-to-regexp@3.2.0": "3.3.0",
"micromatch@<4.0.8": "4.0.8",
"dset@3.1.3": "3.1.4"
"vue": "3.4.27"
},
"packageExtensions": {
"@hoppscotch/httpsnippet": {
"httpsnippet@3.0.1": {
"dependencies": {
"ajv": "6.12.3"
}

View File

@@ -5,7 +5,7 @@
"author": "Hoppscotch (support@hoppscotch.io)",
"license": "MIT",
"scripts": {
"prepare": "rollup -c && tsc --emitDeclarationOnly --declaration"
"prepare": "rollup -c"
},
"type": "module",
"main": "dist/index.cjs",
@@ -25,7 +25,8 @@
"@lezer/generator": "1.5.1",
"mocha": "9.2.2",
"rollup": "3.29.4",
"@rollup/plugin-typescript": "12.1.1",
"rollup-plugin-dts": "6.0.2",
"rollup-plugin-ts": "3.4.5",
"typescript": "5.2.2"
}
}
}

View File

@@ -1,4 +1,4 @@
import typescript from "@rollup/plugin-typescript"
import typescript from "rollup-plugin-ts"
import { lezer } from "@lezer/generator/rollup"
export default {
@@ -8,10 +8,5 @@ export default {
{ file: "dist/index.cjs", format: "cjs" },
{ dir: "./dist", format: "es" },
],
plugins: [
lezer(),
typescript({
tsconfig: "./tsconfig.json"
})
],
plugins: [lezer(), typescript()],
}

View File

@@ -5,7 +5,6 @@
"module": "es2020",
"newLine": "lf",
"declaration": true,
"declarationDir": "./dist",
"moduleResolution": "node",
"allowJs": true
},

View File

@@ -1,3 +0,0 @@
source_url "https://raw.githubusercontent.com/cachix/devenv/95f329d49a8a5289d31e0982652f7058a189bfca/direnvrc" "sha256-d+8cBpDfDBj41inrADaJt+bDWhOktwslgoP5YiGJ1v0="
use devenv

View File

@@ -1,33 +0,0 @@
# Logs
logs
*.log
npm-debug.log*
yarn-debug.log*
yarn-error.log*
pnpm-debug.log*
lerna-debug.log*
node_modules
dist
dist-ssr
*.local
# Editor directories and files
.vscode/*
!.vscode/extensions.json
.idea
.DS_Store
*.suo
*.ntvs*
*.njsproj
*.sln
*.sw?
# Devenv
.devenv*
devenv.local.nix
# direnv
.direnv
# pre-commit
.pre-commit-config.yaml

View File

@@ -1,16 +0,0 @@
# Tauri + Vue + TypeScript
This template should help get you started developing with Vue 3 and TypeScript in Vite. The template uses Vue 3 `<script setup>` SFCs, check out the [script setup docs](https://v3.vuejs.org/api/sfc-script-setup.html#sfc-script-setup) to learn more.
## Recommended IDE Setup
- [VS Code](https://code.visualstudio.com/) + [Volar](https://marketplace.visualstudio.com/items?itemName=Vue.volar) + [Tauri](https://marketplace.visualstudio.com/items?itemName=tauri-apps.tauri-vscode) + [rust-analyzer](https://marketplace.visualstudio.com/items?itemName=rust-lang.rust-analyzer)
## Type Support For `.vue` Imports in TS
Since TypeScript cannot handle type information for `.vue` imports, they are shimmed to be a generic Vue component type by default. In most cases this is fine if you don't really care about component prop types outside of templates. However, if you wish to get actual prop types in `.vue` imports (for example to get props validation when using manual `h(...)` calls), you can enable Volar's Take Over mode by following these steps:
1. Run `Extensions: Show Built-in Extensions` from VS Code's command palette, look for `TypeScript and JavaScript Language Features`, then right click and select `Disable (Workspace)`. By default, Take Over mode will enable itself if the default TypeScript extension is disabled.
2. Reload the VS Code window by running `Developer: Reload Window` from the command palette.
You can learn more about Take Over mode [here](https://github.com/johnsoncodehk/volar/discussions/471).

View File

@@ -1,153 +0,0 @@
{
"nodes": {
"devenv": {
"locked": {
"dir": "src/modules",
"lastModified": 1729277673,
"owner": "cachix",
"repo": "devenv",
"rev": "3c3ab087b53d3e4699a43018ac71b5e1091ed73d",
"type": "github"
},
"original": {
"dir": "src/modules",
"owner": "cachix",
"repo": "devenv",
"type": "github"
}
},
"fenix": {
"inputs": {
"nixpkgs": [
"nixpkgs"
],
"rust-analyzer-src": "rust-analyzer-src"
},
"locked": {
"lastModified": 1728973961,
"owner": "nix-community",
"repo": "fenix",
"rev": "d6a9ff4d1e60c347a23bc96ccdb058d37a810541",
"type": "github"
},
"original": {
"owner": "nix-community",
"repo": "fenix",
"type": "github"
}
},
"flake-compat": {
"flake": false,
"locked": {
"lastModified": 1696426674,
"owner": "edolstra",
"repo": "flake-compat",
"rev": "0f9255e01c2351cc7d116c072cb317785dd33b33",
"type": "github"
},
"original": {
"owner": "edolstra",
"repo": "flake-compat",
"type": "github"
}
},
"gitignore": {
"inputs": {
"nixpkgs": [
"pre-commit-hooks",
"nixpkgs"
]
},
"locked": {
"lastModified": 1709087332,
"owner": "hercules-ci",
"repo": "gitignore.nix",
"rev": "637db329424fd7e46cf4185293b9cc8c88c95394",
"type": "github"
},
"original": {
"owner": "hercules-ci",
"repo": "gitignore.nix",
"type": "github"
}
},
"nixpkgs": {
"locked": {
"lastModified": 1729265718,
"owner": "NixOS",
"repo": "nixpkgs",
"rev": "ccc0c2126893dd20963580b6478d1a10a4512185",
"type": "github"
},
"original": {
"owner": "NixOS",
"ref": "nixpkgs-unstable",
"repo": "nixpkgs",
"type": "github"
}
},
"nixpkgs-stable": {
"locked": {
"lastModified": 1729181673,
"owner": "NixOS",
"repo": "nixpkgs",
"rev": "4eb33fe664af7b41a4c446f87d20c9a0a6321fa3",
"type": "github"
},
"original": {
"owner": "NixOS",
"ref": "nixos-24.05",
"repo": "nixpkgs",
"type": "github"
}
},
"pre-commit-hooks": {
"inputs": {
"flake-compat": "flake-compat",
"gitignore": "gitignore",
"nixpkgs": [
"nixpkgs"
],
"nixpkgs-stable": "nixpkgs-stable"
},
"locked": {
"lastModified": 1729104314,
"owner": "cachix",
"repo": "pre-commit-hooks.nix",
"rev": "3c3e88f0f544d6bb54329832616af7eb971b6be6",
"type": "github"
},
"original": {
"owner": "cachix",
"repo": "pre-commit-hooks.nix",
"type": "github"
}
},
"root": {
"inputs": {
"devenv": "devenv",
"fenix": "fenix",
"nixpkgs": "nixpkgs",
"pre-commit-hooks": "pre-commit-hooks"
}
},
"rust-analyzer-src": {
"flake": false,
"locked": {
"lastModified": 1729259624,
"owner": "rust-lang",
"repo": "rust-analyzer",
"rev": "3ddfb0da474bdf243a655a5d785de9b59c7f1397",
"type": "github"
},
"original": {
"owner": "rust-lang",
"ref": "nightly",
"repo": "rust-analyzer",
"type": "github"
}
}
},
"root": "root",
"version": 7
}

View File

@@ -1,116 +0,0 @@
{ pkgs, lib, config, inputs, ... }:
let
rosettaPkgs =
if pkgs.stdenv.isDarwin && pkgs.stdenv.isAarch64
then pkgs.pkgsx86_64Darwin
else pkgs;
darwinPackages = with pkgs; [
darwin.apple_sdk.frameworks.Security
darwin.apple_sdk.frameworks.CoreServices
darwin.apple_sdk.frameworks.CoreFoundation
darwin.apple_sdk.frameworks.Foundation
darwin.apple_sdk.frameworks.AppKit
darwin.apple_sdk.frameworks.WebKit
];
linuxPackages = with pkgs; [
libsoup_3
webkitgtk_4_1
librsvg
libappindicator
libayatana-appindicator
];
in {
# https://devenv.sh/packages/
packages = with pkgs; [
git
postgresql_16
# FE and Node stuff
nodejs_22
nodePackages_latest.typescript-language-server
nodePackages_latest.vls
nodePackages_latest.prisma
prisma-engines
# Cargo
cargo-edit
] ++ lib.optionals pkgs.stdenv.isDarwin darwinPackages
++ lib.optionals pkgs.stdenv.isLinux linuxPackages;
# https://devenv.sh/basics/
env = {
APP_GREET = "Hoppscotch";
} // lib.optionalAttrs pkgs.stdenv.isLinux {
# NOTE: Setting these `PRISMA_*` environment variable fixes
# Error: Failed to fetch sha256 checksum at https://binaries.prisma.sh/all_commits/<hash>/linux-nixos/libquery_engine.so.node.gz.sha256 - 404 Not Found
# See: https://github.com/prisma/prisma/discussions/3120
PRISMA_QUERY_ENGINE_LIBRARY = "${pkgs.prisma-engines}/lib/libquery_engine.node";
PRISMA_QUERY_ENGINE_BINARY = "${pkgs.prisma-engines}/bin/query-engine";
PRISMA_SCHEMA_ENGINE_BINARY = "${pkgs.prisma-engines}/bin/schema-engine";
LD_LIBRARY_PATH = lib.makeLibraryPath [
pkgs.libappindicator
pkgs.libayatana-appindicator
];
} // lib.optionalAttrs pkgs.stdenv.isDarwin {
# Place to put macOS-specific environment variables
};
# https://devenv.sh/scripts/
scripts = {
hello.exec = "echo hello from $APP_GREET";
e.exec = "emacs";
};
enterShell = ''
git --version
${lib.optionalString pkgs.stdenv.isDarwin ''
# Place to put macOS-specific shell initialization
''}
${lib.optionalString pkgs.stdenv.isLinux ''
# Place to put Linux-specific shell initialization
''}
'';
# https://devenv.sh/tests/
enterTest = ''
echo "Running tests"
'';
# https://devenv.sh/integrations/dotenv/
dotenv.enable = true;
# https://devenv.sh/languages/
languages = {
typescript.enable = true;
javascript = {
enable = true;
pnpm.enable = true;
npm.enable = true;
};
rust = {
enable = true;
channel = "nightly";
components = [
"rustc"
"cargo"
"clippy"
"rustfmt"
"rust-analyzer"
"llvm-tools-preview"
"rust-src"
"rustc-codegen-cranelift-preview"
];
};
};
# https://devenv.sh/pre-commit-hooks/
# pre-commit.hooks.shellcheck.enable = true;
# https://devenv.sh/processes/
# processes.ping.exec = "ping example.com";
# See full reference at https://devenv.sh/reference/options/
}

View File

@@ -1,23 +0,0 @@
# yaml-language-server: $schema=https://devenv.sh/devenv.schema.json
inputs:
# For NodeJS-22 and above
nixpkgs:
url: github:NixOS/nixpkgs/nixpkgs-unstable
# nixpkgs:
# url: github:cachix/devenv-nixpkgs/rolling
fenix:
url: github:nix-community/fenix
inputs:
nixpkgs:
follows: nixpkgs
# If you're using non-OSS software, you can set allowUnfree to true.
allowUnfree: true
# If you're willing to use a package that's vulnerable
# permittedInsecurePackages:
# - "openssl-1.1.1w"
# If you have more than one devenv you can merge them
#imports:
# - ./backend

View File

@@ -1,13 +0,0 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<link rel="icon" type="image/svg+xml" href="/vite.svg" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Hoppscotch Agent</title>
</head>
<body>
<div id="app"></div>
<script type="module" src="/src/main.ts"></script>
</body>
</html>

View File

@@ -1,34 +0,0 @@
{
"name": "hoppscotch-agent",
"private": true,
"version": "0.1.3",
"type": "module",
"scripts": {
"dev": "vite",
"build": "vue-tsc --noEmit && vite build",
"preview": "vite preview",
"tauri": "tauri"
},
"dependencies": {
"@hoppscotch/ui": "^0.2.1",
"@tauri-apps/api": "^2.0.2",
"@tauri-apps/plugin-shell": "^2.0.0",
"@vueuse/core": "^11.1.0",
"axios": "^1.7.7",
"fp-ts": "^2.16.9",
"vue": "3.3.9"
},
"devDependencies": {
"@iconify-json/lucide": "^1.2.8",
"@tauri-apps/cli": "^2.0.3",
"@types/node": "^22.7.5",
"@vitejs/plugin-vue": "^5.1.4",
"autoprefixer": "^10.4.20",
"postcss": "^8.4.47",
"tailwindcss": "^3.4.13",
"typescript": "^5.6.3",
"unplugin-icons": "^0.19.3",
"vite": "^5.4.8",
"vue-tsc": "^2.1.6"
}
}

File diff suppressed because it is too large Load Diff

View File

@@ -1,6 +0,0 @@
export default {
plugins: {
tailwindcss: {},
autoprefixer: {},
},
}

View File

@@ -1,6 +0,0 @@
<svg width="206" height="231" viewBox="0 0 206 231" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M143.143 84C143.143 96.1503 133.293 106 121.143 106C108.992 106 99.1426 96.1503 99.1426 84C99.1426 71.8497 108.992 62 121.143 62C133.293 62 143.143 71.8497 143.143 84Z" fill="#FFC131"/>
<ellipse cx="84.1426" cy="147" rx="22" ry="22" transform="rotate(180 84.1426 147)" fill="#24C8DB"/>
<path fill-rule="evenodd" clip-rule="evenodd" d="M166.738 154.548C157.86 160.286 148.023 164.269 137.757 166.341C139.858 160.282 141 153.774 141 147C141 144.543 140.85 142.121 140.558 139.743C144.975 138.204 149.215 136.139 153.183 133.575C162.73 127.404 170.292 118.608 174.961 108.244C179.63 97.8797 181.207 86.3876 179.502 75.1487C177.798 63.9098 172.884 53.4021 165.352 44.8883C157.82 36.3744 147.99 30.2165 137.042 27.1546C126.095 24.0926 114.496 24.2568 103.64 27.6274C92.7839 30.998 83.1319 37.4317 75.8437 46.1553C74.9102 47.2727 74.0206 48.4216 73.176 49.5993C61.9292 50.8488 51.0363 54.0318 40.9629 58.9556C44.2417 48.4586 49.5653 38.6591 56.679 30.1442C67.0505 17.7298 80.7861 8.57426 96.2354 3.77762C111.685 -1.01901 128.19 -1.25267 143.769 3.10474C159.348 7.46215 173.337 16.2252 184.056 28.3411C194.775 40.457 201.767 55.4101 204.193 71.404C206.619 87.3978 204.374 103.752 197.73 118.501C191.086 133.25 180.324 145.767 166.738 154.548ZM41.9631 74.275L62.5557 76.8042C63.0459 72.813 63.9401 68.9018 65.2138 65.1274C57.0465 67.0016 49.2088 70.087 41.9631 74.275Z" fill="#FFC131"/>
<path fill-rule="evenodd" clip-rule="evenodd" d="M38.4045 76.4519C47.3493 70.6709 57.2677 66.6712 67.6171 64.6132C65.2774 70.9669 64 77.8343 64 85.0001C64 87.1434 64.1143 89.26 64.3371 91.3442C60.0093 92.8732 55.8533 94.9092 51.9599 97.4256C42.4128 103.596 34.8505 112.392 30.1816 122.756C25.5126 133.12 23.9357 144.612 25.6403 155.851C27.3449 167.09 32.2584 177.598 39.7906 186.112C47.3227 194.626 57.153 200.784 68.1003 203.846C79.0476 206.907 90.6462 206.743 101.502 203.373C112.359 200.002 122.011 193.568 129.299 184.845C130.237 183.722 131.131 182.567 131.979 181.383C143.235 180.114 154.132 176.91 164.205 171.962C160.929 182.49 155.596 192.319 148.464 200.856C138.092 213.27 124.357 222.426 108.907 227.222C93.458 232.019 76.9524 232.253 61.3736 227.895C45.7948 223.538 31.8055 214.775 21.0867 202.659C10.3679 190.543 3.37557 175.59 0.949823 159.596C-1.47592 143.602 0.768139 127.248 7.41237 112.499C14.0566 97.7497 24.8183 85.2327 38.4045 76.4519ZM163.062 156.711L163.062 156.711C162.954 156.773 162.846 156.835 162.738 156.897C162.846 156.835 162.954 156.773 163.062 156.711Z" fill="#24C8DB"/>
</svg>

Before

Width:  |  Height:  |  Size: 2.5 KiB

View File

@@ -1 +0,0 @@
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" aria-hidden="true" role="img" class="iconify iconify--logos" width="31.88" height="32" preserveAspectRatio="xMidYMid meet" viewBox="0 0 256 257"><defs><linearGradient id="IconifyId1813088fe1fbc01fb466" x1="-.828%" x2="57.636%" y1="7.652%" y2="78.411%"><stop offset="0%" stop-color="#41D1FF"></stop><stop offset="100%" stop-color="#BD34FE"></stop></linearGradient><linearGradient id="IconifyId1813088fe1fbc01fb467" x1="43.376%" x2="50.316%" y1="2.242%" y2="89.03%"><stop offset="0%" stop-color="#FFEA83"></stop><stop offset="8.333%" stop-color="#FFDD35"></stop><stop offset="100%" stop-color="#FFA800"></stop></linearGradient></defs><path fill="url(#IconifyId1813088fe1fbc01fb466)" d="M255.153 37.938L134.897 252.976c-2.483 4.44-8.862 4.466-11.382.048L.875 37.958c-2.746-4.814 1.371-10.646 6.827-9.67l120.385 21.517a6.537 6.537 0 0 0 2.322-.004l117.867-21.483c5.438-.991 9.574 4.796 6.877 9.62Z"></path><path fill="url(#IconifyId1813088fe1fbc01fb467)" d="M185.432.063L96.44 17.501a3.268 3.268 0 0 0-2.634 3.014l-5.474 92.456a3.268 3.268 0 0 0 3.997 3.378l24.777-5.718c2.318-.535 4.413 1.507 3.936 3.838l-7.361 36.047c-.495 2.426 1.782 4.5 4.151 3.78l15.304-4.649c2.372-.72 4.652 1.36 4.15 3.788l-11.698 56.621c-.732 3.542 3.979 5.473 5.943 2.437l1.313-2.028l72.516-144.72c1.215-2.423-.88-5.186-3.54-4.672l-25.505 4.922c-2.396.462-4.435-1.77-3.759-4.114l16.646-57.705c.677-2.35-1.37-4.583-3.769-4.113Z"></path></svg>

Before

Width:  |  Height:  |  Size: 1.5 KiB

View File

@@ -1,25 +0,0 @@
# Enable static linking for C runtime library on Windows.
#
# Rust uses the msvc toolchain on Windows,
# which by default dynamically links the C runtime (CRT) to the binary.
#
# This creates a runtime dependency on the Visual C++ Redistributable (`vcredist`),
# meaning the target machine must have `vcredist` installed for the application to run.
#
# Since `portable` version doesn't have an installer,
# we can't rely on it to install dependencies, so this config.
#
# Basically:
# - The `+crt-static` flag instructs the Rust compiler to statically link the C runtime for Windows builds.\
# - To avoids runtime errors related to missing `vcredist` installations.
# - Results in a larger binary size because the runtime is bundled directly into the executable.
#
# For MSVC targets specifically, it will compile code with `/MT` or static linkage.
# See: - RFC 1721: https://rust-lang.github.io/rfcs/1721-crt-static.html
# - Rust Reference - Runtime: https://doc.rust-lang.org/reference/runtime.html
# - MSVC Linking Options: https://docs.microsoft.com/en-us/cpp/build/reference/md-mt-ld-use-run-time-library
# - Rust Issue #37406: https://github.com/rust-lang/rust/issues/37406
# - Tauri Issue #3048: https://github.com/tauri-apps/tauri/issues/3048
# - Rust Linkage: https://doc.rust-lang.org/reference/linkage.html
[target.'cfg(windows)']
rustflags = ["-C", "target-feature=+crt-static"]

View File

@@ -1,7 +0,0 @@
# Generated by Cargo
# will have compiled files and executables
/target/
# Generated by Tauri
# will have schema files for capabilities auto-completion
/gen/schemas

File diff suppressed because it is too large Load Diff

View File

@@ -1,56 +0,0 @@
[package]
name = "hoppscotch-agent"
version = "0.1.3"
description = "A cross-platform HTTP request agent for Hoppscotch for advanced request handling including custom headers, certificates, proxies, and local system integration."
authors = ["AndrewBastin", "CuriousCorrelation"]
edition = "2021"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[lib]
name = "hoppscotch_agent_lib"
crate-type = ["staticlib", "cdylib", "rlib"]
[build-dependencies]
tauri-build = { version = "2.0.1", features = [] }
[dependencies]
tauri = { version = "2.0.4", features = ["tray-icon", "image-png"] }
tauri-plugin-shell = "2.0.1"
tauri-plugin-autostart = { version = "2.0.1", optional = true }
serde = { version = "1", features = ["derive"] }
serde_json = "1"
tokio = { version = "1.40.0", features = ["full"] }
dashmap = { version = "6.1.0", features = ["serde"] }
axum = { version = "0.7.7" }
axum-extra = { version = "0.9.4", features = ["typed-header"] }
tower-http = { version = "0.6.1", features = ["cors"] }
tokio-util = "0.7.12"
uuid = { version = "1.11.0", features = [ "v4", "fast-rng" ] }
chrono = { version = "0.4", features = ["serde"] }
rand = "0.8.5"
log = "0.4.22"
env_logger = "0.11.5"
hoppscotch-relay = { path = "../../hoppscotch-relay" }
thiserror = "1.0.64"
tauri-plugin-store = "2.1.0"
x25519-dalek = { version = "2.0.1", features = ["getrandom"] }
base16 = "0.2.1"
aes-gcm = { version = "0.10.3", features = ["aes"] }
tauri-plugin-updater = "2.0.2"
tauri-plugin-dialog = "2.0.1"
lazy_static = "1.5.0"
tauri-plugin-single-instance = "2.0.1"
tauri-plugin-http = { version = "2.0.1", features = ["gzip"] }
native-dialog = "0.7.0"
[target.'cfg(windows)'.dependencies]
tempfile = { version = "3.13.0" }
winreg = { version = "0.52.0" }
[dev-dependencies]
mockito = "1.5.0"
[features]
default = ["tauri-plugin-autostart"]
portable = []

View File

@@ -1,5 +0,0 @@
fn main() {
tauri_build::build();
println!("cargo::rerun-if-env-changed=UPDATER_PUB_KEY");
println!("cargo::rerun-if-env-changed=UPDATER_URL");
}

View File

@@ -1,24 +0,0 @@
{
"$schema": "../gen/schemas/desktop-schema.json",
"identifier": "default",
"description": "Capability for the main window",
"windows": ["main", "test"],
"permissions": [
{
"identifier": "http:default",
"allow": [
{
"url": "https://*.tauri.app"
},
{
"url": "https://*.microsoft.*"
}
]
},
"core:default",
"shell:allow-open",
"core:window:allow-close",
"core:window:allow-set-focus",
"core:window:allow-set-always-on-top"
]
}

Binary file not shown.

Before

Width:  |  Height:  |  Size: 13 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 37 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.9 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 9.7 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 15 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 16 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 44 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.7 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 52 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.8 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.6 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 7.5 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.4 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 18 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 10 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 8.4 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 28 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 8.4 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 15 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 56 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 15 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 23 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 98 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 23 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 50 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 135 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 948 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.4 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.4 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.5 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.0 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.0 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 7.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.4 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 6.4 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 6.4 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 12 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 545 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 12 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 21 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 6.0 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 16 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 19 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.2 KiB

View File

@@ -1,220 +0,0 @@
use axum::{
body::Bytes,
extract::{Path, State},
http::HeaderMap,
Json,
};
use axum_extra::{
headers::{authorization::Bearer, Authorization},
TypedHeader,
};
use hoppscotch_relay::{RequestWithMetadata, ResponseWithMetadata};
use std::sync::Arc;
use tauri::{AppHandle, Emitter};
use x25519_dalek::{EphemeralSecret, PublicKey};
use crate::{
error::{AgentError, AgentResult},
model::{AuthKeyResponse, ConfirmedRegistrationRequest, HandshakeResponse},
state::{AppState, Registration},
util::EncryptedJson,
};
use chrono::Utc;
use rand::Rng;
use serde_json::json;
use uuid::Uuid;
fn generate_otp() -> String {
let otp: u32 = rand::thread_rng().gen_range(0..1_000_000);
format!("{:06}", otp)
}
pub async fn handshake(
State((_, app_handle)): State<(Arc<AppState>, AppHandle)>,
) -> AgentResult<Json<HandshakeResponse>> {
Ok(Json(HandshakeResponse {
status: "success".to_string(),
__hoppscotch__agent__: true,
agent_version: app_handle.package_info().version.to_string(),
}))
}
pub async fn receive_registration(
State((state, app_handle)): State<(Arc<AppState>, AppHandle)>,
) -> AgentResult<Json<serde_json::Value>> {
let otp = generate_otp();
let mut active_registration_code = state.active_registration_code.write().await;
if !active_registration_code.is_none() {
return Ok(Json(
json!({ "message": "There is already an existing registration happening" }),
));
}
*active_registration_code = Some(otp.clone());
app_handle
.emit("registration_received", otp)
.map_err(|_| AgentError::InternalServerError)?;
Ok(Json(
json!({ "message": "Registration received and stored" }),
))
}
pub async fn verify_registration(
State((state, app_handle)): State<(Arc<AppState>, AppHandle)>,
Json(confirmed_registration): Json<ConfirmedRegistrationRequest>,
) -> AgentResult<Json<AuthKeyResponse>> {
state
.validate_registration(&confirmed_registration.registration)
.await
.then_some(())
.ok_or(AgentError::InvalidRegistration)?;
let auth_key = Uuid::new_v4().to_string();
let created_at = Utc::now();
let auth_key_copy = auth_key.clone();
let agent_secret_key = EphemeralSecret::random();
let agent_public_key = PublicKey::from(&agent_secret_key);
let their_public_key = {
let public_key_slice: &[u8; 32] =
&base16::decode(&confirmed_registration.client_public_key_b16)
.map_err(|_| AgentError::InvalidClientPublicKey)?[0..32]
.try_into()
.map_err(|_| AgentError::InvalidClientPublicKey)?;
PublicKey::from(public_key_slice.to_owned())
};
let shared_secret = agent_secret_key.diffie_hellman(&their_public_key);
let _ = state.update_registrations(app_handle.clone(), |regs| {
regs.insert(
auth_key_copy,
Registration {
registered_at: created_at,
shared_secret_b16: base16::encode_lower(shared_secret.as_bytes()),
},
);
})?;
let auth_payload = json!({
"auth_key": auth_key,
"created_at": created_at
});
app_handle
.emit("authenticated", &auth_payload)
.map_err(|_| AgentError::InternalServerError)?;
Ok(Json(AuthKeyResponse {
auth_key,
created_at,
agent_public_key_b16: base16::encode_lower(agent_public_key.as_bytes()),
}))
}
pub async fn run_request<T>(
State((state, _app_handle)): State<(Arc<AppState>, T)>,
TypedHeader(auth_header): TypedHeader<Authorization<Bearer>>,
headers: HeaderMap,
body: Bytes,
) -> AgentResult<EncryptedJson<ResponseWithMetadata>> {
let nonce = headers
.get("X-Hopp-Nonce")
.ok_or(AgentError::Unauthorized)?
.to_str()
.map_err(|_| AgentError::Unauthorized)?;
let req: RequestWithMetadata = state
.validate_access_and_get_data(auth_header.token(), nonce, &body)
.ok_or(AgentError::Unauthorized)?;
let req_id = req.req_id;
let reg_info = state
.get_registration_info(auth_header.token())
.ok_or(AgentError::Unauthorized)?;
let cancel_token = tokio_util::sync::CancellationToken::new();
state.add_cancellation_token(req.req_id, cancel_token.clone());
let cancel_token_clone = cancel_token.clone();
// Execute the HTTP request in a blocking thread pool and handles cancellation.
//
// It:
// 1. Uses `spawn_blocking` to run the sync `run_request_task`
// without blocking the main Tokio runtime.
// 2. Uses `select!` to concurrently wait for either
// a. the task to complete,
// b. or a cancellation signal.
//
// Why spawn_blocking?
// - `run_request_task` uses synchronous curl operations which would block
// the async runtime if not run in a separate thread.
// - `spawn_blocking` moves this operation to a thread pool designed for
// blocking tasks, so other async operations to continue unblocked.
let result = tokio::select! {
res = tokio::task::spawn_blocking(move || hoppscotch_relay::run_request_task(&req, cancel_token_clone)) => {
match res {
Ok(task_result) => Ok(task_result?),
Err(_) => Err(AgentError::InternalServerError),
}
},
_ = cancel_token.cancelled() => {
Err(AgentError::RequestCancelled)
}
};
state.remove_cancellation_token(req_id);
result.map(|val| EncryptedJson {
key_b16: reg_info.shared_secret_b16,
data: val,
})
}
/// Provides a way for registered clients to check if their
/// registration still holds, this route is supposed to return
/// an encrypted `true` value if the given auth_key is good.
/// Since its encrypted with the shared secret established during
/// registration, the client also needs the shared secret to verify
/// if the read fails, or the auth_key didn't validate and this route returns
/// undefined, we can count on the registration not being valid anymore.
pub async fn registered_handshake(
State((state, _)): State<(Arc<AppState>, AppHandle)>,
TypedHeader(auth_header): TypedHeader<Authorization<Bearer>>,
) -> AgentResult<EncryptedJson<serde_json::Value>> {
let reg_info = state.get_registration_info(auth_header.token());
match reg_info {
Some(reg) => Ok(EncryptedJson {
key_b16: reg.shared_secret_b16,
data: json!(true),
}),
None => Err(AgentError::Unauthorized),
}
}
pub async fn cancel_request<T>(
State((state, _app_handle)): State<(Arc<AppState>, T)>,
TypedHeader(auth_header): TypedHeader<Authorization<Bearer>>,
Path(req_id): Path<usize>,
) -> AgentResult<Json<serde_json::Value>> {
if !state.validate_access(auth_header.token()) {
return Err(AgentError::Unauthorized);
}
if let Some((_, token)) = state.remove_cancellation_token(req_id) {
token.cancel();
Ok(Json(json!({"message": "Request cancelled successfully"})))
} else {
Err(AgentError::RequestNotFound)
}
}

View File

@@ -1,58 +0,0 @@
use native_dialog::{MessageDialog, MessageType};
pub fn panic(msg: &str) {
const FATAL_ERROR: &str = "Fatal error";
MessageDialog::new()
.set_type(MessageType::Error)
.set_title(FATAL_ERROR)
.set_text(msg)
.show_alert()
.unwrap_or_default();
log::error!("{}: {}", FATAL_ERROR, msg);
panic!("{}: {}", FATAL_ERROR, msg);
}
pub fn info(msg: &str) {
log::info!("{}", msg);
MessageDialog::new()
.set_type(MessageType::Info)
.set_title("Info")
.set_text(msg)
.show_alert()
.unwrap_or_default();
}
pub fn warn(msg: &str) {
log::warn!("{}", msg);
MessageDialog::new()
.set_type(MessageType::Warning)
.set_title("Warning")
.set_text(msg)
.show_alert()
.unwrap_or_default();
}
pub fn error(msg: &str) {
log::error!("{}", msg);
MessageDialog::new()
.set_type(MessageType::Error)
.set_title("Error")
.set_text(msg)
.show_alert()
.unwrap_or_default();
}
pub fn confirm(title: &str, msg: &str, icon: MessageType) -> bool {
MessageDialog::new()
.set_type(icon)
.set_title(title)
.set_text(msg)
.show_confirm()
.unwrap_or_default()
}

View File

@@ -1,81 +0,0 @@
use axum::{
http::StatusCode,
response::{IntoResponse, Response},
Json,
};
use serde_json::json;
use thiserror::Error;
#[derive(Error, Debug)]
pub enum AgentError {
#[error("Invalid Registration")]
InvalidRegistration,
#[error("Invalid Client Public Key")]
InvalidClientPublicKey,
#[error("Unauthorized")]
Unauthorized,
#[error("Request not found or already completed")]
RequestNotFound,
#[error("Internal server error")]
InternalServerError,
#[error("Invalid request: {0}")]
BadRequest(String),
#[error("Client certificate error")]
ClientCertError,
#[error("Root certificate error")]
RootCertError,
#[error("Invalid method")]
InvalidMethod,
#[error("Invalid URL")]
InvalidUrl,
#[error("Invalid headers")]
InvalidHeaders,
#[error("Request run error: {0}")]
RequestRunError(String),
#[error("Request cancelled")]
RequestCancelled,
#[error("Failed to clear registrations")]
RegistrationClearError,
#[error("Failed to insert registrations")]
RegistrationInsertError,
#[error("Failed to save registrations to store")]
RegistrationSaveError,
#[error("Serde error: {0}")]
Serde(#[from] serde_json::Error),
#[error("Store error: {0}")]
TauriPluginStore(#[from] tauri_plugin_store::Error),
#[error("Relay error: {0}")]
Relay(#[from] hoppscotch_relay::RelayError),
}
impl IntoResponse for AgentError {
fn into_response(self) -> Response {
let (status, error_message) = match self {
AgentError::InvalidRegistration => (StatusCode::BAD_REQUEST, self.to_string()),
AgentError::InvalidClientPublicKey => (StatusCode::BAD_REQUEST, self.to_string()),
AgentError::Unauthorized => (StatusCode::UNAUTHORIZED, self.to_string()),
AgentError::RequestNotFound => (StatusCode::NOT_FOUND, self.to_string()),
AgentError::InternalServerError => (StatusCode::INTERNAL_SERVER_ERROR, self.to_string()),
AgentError::BadRequest(msg) => (StatusCode::BAD_REQUEST, msg),
AgentError::ClientCertError => (StatusCode::BAD_REQUEST, self.to_string()),
AgentError::RootCertError => (StatusCode::BAD_REQUEST, self.to_string()),
AgentError::InvalidMethod => (StatusCode::BAD_REQUEST, self.to_string()),
AgentError::InvalidUrl => (StatusCode::BAD_REQUEST, self.to_string()),
AgentError::InvalidHeaders => (StatusCode::BAD_REQUEST, self.to_string()),
AgentError::RequestRunError(msg) => (StatusCode::INTERNAL_SERVER_ERROR, msg),
AgentError::RequestCancelled => (StatusCode::BAD_REQUEST, self.to_string()),
_ => (
StatusCode::INTERNAL_SERVER_ERROR,
"Internal Server Error".to_string(),
),
};
let body = Json(json!({
"error": error_message,
}));
(status, body).into_response()
}
}
pub type AgentResult<T> = std::result::Result<T, AgentError>;

View File

@@ -1,2 +0,0 @@
pub const AGENT_STORE: &str = "app_data.bin";
pub const REGISTRATIONS: &str = "registrations";

View File

@@ -1,178 +0,0 @@
pub mod controller;
pub mod dialog;
pub mod error;
pub mod global;
pub mod model;
pub mod route;
pub mod server;
pub mod state;
pub mod tray;
pub mod updater;
pub mod util;
pub mod webview;
use log::{error, info};
use std::sync::Arc;
use tauri::{Emitter, Listener, Manager, WebviewWindowBuilder};
use tauri_plugin_updater::UpdaterExt;
use tokio_util::sync::CancellationToken;
use model::Payload;
use state::AppState;
#[tauri::command]
async fn get_otp(state: tauri::State<'_, Arc<AppState>>) -> Result<Option<String>, ()> {
Ok(state.active_registration_code.read().await.clone())
}
#[cfg_attr(mobile, tauri::mobile_entry_point)]
pub fn run() {
env_logger::init();
// The installer takes care of installing `WebView`,
// this check is only required for portable variant.
#[cfg(all(feature = "portable", windows))]
webview::init_webview();
let cancellation_token = CancellationToken::new();
let server_cancellation_token = cancellation_token.clone();
tauri::Builder::default()
// NOTE: Currently, plugins run in the order they were added in to the builder,
// so `tauri_plugin_single_instance` needs to be registered first.
// See: https://github.com/tauri-apps/plugins-workspace/tree/v2/plugins/single-instance
.plugin(tauri_plugin_single_instance::init(|app, args, cwd| {
info!("{}, {args:?}, {cwd}", app.package_info().name);
app.emit("single-instance", Payload::new(args, cwd))
.unwrap();
// Application is already running, bring it to foreground.
if let Some(window) = app.get_webview_window("main") {
let _ = window.show();
let _ = window.set_focus();
} else {
error!("Failed to get `main` window");
}
}))
.plugin(tauri_plugin_store::Builder::new().build())
.setup(move |app| {
let app_handle = app.app_handle();
#[cfg(all(desktop, not(feature = "portable")))]
{
use tauri_plugin_autostart::MacosLauncher;
use tauri_plugin_autostart::ManagerExt;
let _ = app.handle().plugin(tauri_plugin_autostart::init(
MacosLauncher::LaunchAgent,
None,
));
let autostart_manager = app.autolaunch();
println!(
"autostart enabled: {}",
autostart_manager.is_enabled().unwrap()
);
if !autostart_manager.is_enabled().unwrap() {
let _ = autostart_manager.enable();
println!(
"autostart updated: {}",
autostart_manager.is_enabled().unwrap()
);
}
};
#[cfg(desktop)]
{
let _ = app
.handle()
.plugin(tauri_plugin_updater::Builder::new().build());
let _ = app.handle().plugin(tauri_plugin_dialog::init());
let updater = app.updater_builder().build().unwrap();
let app_handle_ref = app_handle.clone();
tauri::async_runtime::spawn_blocking(|| {
tauri::async_runtime::block_on(async {
updater::check_and_install_updates(app_handle_ref, updater).await;
})
});
};
let app_state = Arc::new(AppState::new(app_handle.clone())?);
app.manage(app_state.clone());
let server_cancellation_token = server_cancellation_token.clone();
let server_app_handle = app_handle.clone();
tauri::async_runtime::spawn(async move {
server::run_server(app_state, server_cancellation_token, server_app_handle).await;
});
#[cfg(all(desktop))]
{
let handle = app.handle();
tray::create_tray(handle)?;
}
// Blocks the app from populating the macOS dock
#[cfg(target_os = "macos")]
{
app_handle
.set_activation_policy(tauri::ActivationPolicy::Accessory)
.unwrap();
};
let app_handle_ref = app_handle.clone();
app_handle.listen("registration_received", move |_| {
WebviewWindowBuilder::from_config(
&app_handle_ref,
&app_handle_ref.config().app.windows[0],
)
.unwrap()
.build()
.unwrap()
.show()
.unwrap();
});
Ok(())
})
.manage(cancellation_token)
.on_window_event(|window, event| {
match &event {
tauri::WindowEvent::CloseRequested { .. } => {
let app_state = window.state::<Arc<AppState>>();
let mut current_code = app_state.active_registration_code.blocking_write();
if current_code.is_some() {
*current_code = None;
}
}
_ => {}
};
})
.invoke_handler(tauri::generate_handler![get_otp])
.build(tauri::generate_context!())
.expect("error while building tauri application")
.run(|app_handle, event| match event {
tauri::RunEvent::ExitRequested { api, code, .. } => {
if code.is_none() || matches!(code, Some(0)) {
api.prevent_exit()
} else if code.is_some() {
let state = app_handle.state::<CancellationToken>();
state.cancel();
}
}
_ => {}
});
}

View File

@@ -1,6 +0,0 @@
// Prevents additional console window on Windows in release, DO NOT REMOVE!!
#![cfg_attr(not(debug_assertions), windows_subsystem = "windows")]
fn main() {
hoppscotch_agent_lib::run()
}

View File

@@ -1,47 +0,0 @@
use chrono::{DateTime, Utc};
use serde::{Deserialize, Serialize};
/// Single instance payload.
#[derive(Clone, Serialize)]
pub struct Payload {
args: Vec<String>,
cwd: String,
}
impl Payload {
pub fn new(args: Vec<String>, cwd: String) -> Self {
Self { args, cwd }
}
}
#[derive(Debug, Serialize, Deserialize)]
pub struct HandshakeResponse {
#[allow(non_snake_case)]
pub __hoppscotch__agent__: bool,
pub status: String,
pub agent_version: String,
}
#[derive(Debug, Serialize, Deserialize)]
pub struct ConfirmedRegistrationRequest {
pub registration: String,
/// base16 (lowercase) encoded public key shared by the client
/// to the agent so that the agent can establish a shared secret
/// which will be used to encrypt traffic between agent
/// and client after registration
pub client_public_key_b16: String,
}
#[derive(Debug, Serialize, Deserialize)]
pub struct AuthKeyResponse {
pub auth_key: String,
pub created_at: DateTime<Utc>,
/// base16 (lowercase) encoded public key shared by the
/// agent so that the client can establish a shared secret
/// which will be used to encrypt traffic between agent
/// and client after registration
pub agent_public_key_b16: String,
}

View File

@@ -1,28 +0,0 @@
use axum::{
routing::{get, post},
Router,
};
use std::sync::Arc;
use tauri::AppHandle;
use crate::{controller, state::AppState};
pub fn route(state: Arc<AppState>, app_handle: AppHandle) -> Router {
Router::new()
.route("/handshake", get(controller::handshake))
.route(
"/receive-registration",
post(controller::receive_registration),
)
.route(
"/verify-registration",
post(controller::verify_registration),
)
.route(
"/registered-handshake",
get(controller::registered_handshake),
)
.route("/request", post(controller::run_request))
.route("/cancel-request/:req_id", post(controller::cancel_request))
.with_state((state, app_handle))
}

View File

@@ -1,34 +0,0 @@
use axum::Router;
use std::sync::Arc;
use tokio_util::sync::CancellationToken;
use tower_http::cors::CorsLayer;
use crate::route;
use crate::state::AppState;
pub async fn run_server(
state: Arc<AppState>,
cancellation_token: CancellationToken,
app_handle: tauri::AppHandle,
) {
let cors = CorsLayer::permissive();
let app = Router::new()
.merge(route::route(state, app_handle))
.layer(cors);
let addr = std::net::SocketAddr::from(([127, 0, 0, 1], 9119));
println!("Server running on http://{}", addr);
let listener = tokio::net::TcpListener::bind(&addr).await.unwrap();
axum::serve(listener, app.into_make_service())
.with_graceful_shutdown(async move {
cancellation_token.cancelled().await;
})
.await
.unwrap();
println!("Server shut down");
}

Some files were not shown because too many files have changed in this diff Show More