diff --git a/api-tests/Addresses/Create Address.bru b/api-tests/Addresses/Create Address.bru new file mode 100644 index 0000000..85b3e31 --- /dev/null +++ b/api-tests/Addresses/Create Address.bru @@ -0,0 +1,33 @@ +meta { + name: Create Address + type: http + seq: 1 +} + +post { + url: {{base_url}}/v1/wallets/{{wallet_id}}/addresses + body: json + auth: none +} + +headers { + authorization: Bearer {{token}} +} + +body:json { + { + "customer_ref": "test-customer-1", + "metadata": { "plan": "pro" } + } +} + +script:post-response { + if (res.body?.data?.id) { + bru.setVar("address_id", res.body.data.id); + } +} + +docs { + Generates a dedicated deposit address (muxed M... plus a G...+memo fallback) instantly, + off-chain. Both forms credit the same master wallet — there's nothing to sweep. +} diff --git a/api-tests/Addresses/List Addresses.bru b/api-tests/Addresses/List Addresses.bru new file mode 100644 index 0000000..230aa5c --- /dev/null +++ b/api-tests/Addresses/List Addresses.bru @@ -0,0 +1,14 @@ +meta { + name: List Addresses + type: http + seq: 2 +} + +get { + url: {{base_url}}/v1/wallets/{{wallet_id}}/addresses + auth: none +} + +headers { + authorization: Bearer {{token}} +} diff --git a/api-tests/Auth/Login.bru b/api-tests/Auth/Login.bru new file mode 100644 index 0000000..8ca0118 --- /dev/null +++ b/api-tests/Auth/Login.bru @@ -0,0 +1,29 @@ +meta { + name: Login + type: http + seq: 2 +} + +post { + url: {{base_url}}/v1/auth/login + body: json + auth: none +} + +body:json { + { + "email": "your-existing-user@octo.test", + "password": "supersecret123" + } +} + +script:post-response { + if (res.body?.data?.token) { + bru.setVar("token", res.body.data.token); + } +} + +docs { + Log in an existing user. Edit the email/password to match a real account, or just re-run + Signup instead if you don't need a persistent one. +} diff --git a/api-tests/Auth/Logout.bru b/api-tests/Auth/Logout.bru new file mode 100644 index 0000000..9c49c4d --- /dev/null +++ b/api-tests/Auth/Logout.bru @@ -0,0 +1,18 @@ +meta { + name: Logout + type: http + seq: 5 +} + +post { + url: {{base_url}}/v1/auth/logout + auth: none +} + +headers { + authorization: Bearer {{token}} +} + +docs { + Revokes the current token. Every other request will 401 until you Signup/Login again. +} diff --git a/api-tests/Auth/Me.bru b/api-tests/Auth/Me.bru new file mode 100644 index 0000000..bb7bfac --- /dev/null +++ b/api-tests/Auth/Me.bru @@ -0,0 +1,18 @@ +meta { + name: Me + type: http + seq: 3 +} + +get { + url: {{base_url}}/v1/auth/me + auth: none +} + +headers { + authorization: Bearer {{token}} +} + +docs { + Returns the authenticated user. Confirms the token from Signup/Login is still valid. +} diff --git a/api-tests/Auth/Refresh.bru b/api-tests/Auth/Refresh.bru new file mode 100644 index 0000000..d163075 --- /dev/null +++ b/api-tests/Auth/Refresh.bru @@ -0,0 +1,24 @@ +meta { + name: Refresh + type: http + seq: 4 +} + +post { + url: {{base_url}}/v1/auth/refresh + auth: none +} + +headers { + authorization: Bearer {{token}} +} + +script:post-response { + if (res.body?.data?.token) { + bru.setVar("token", res.body.data.token); + } +} + +docs { + Issues a fresh token for an already-valid session and auto-saves it, replacing the old one. +} diff --git a/api-tests/Auth/Signup.bru b/api-tests/Auth/Signup.bru new file mode 100644 index 0000000..674aeb4 --- /dev/null +++ b/api-tests/Auth/Signup.bru @@ -0,0 +1,33 @@ +meta { + name: Signup + type: http + seq: 1 +} + +post { + url: {{base_url}}/v1/auth/signup + body: json + auth: none +} + +body:json { + { + "email": "test-{{$randomInt}}@octo.test", + "password": "supersecret123" + } +} + +script:post-response { + if (res.body?.data?.token) { + bru.setVar("token", res.body.data.token); + bru.setVar("user_id", res.body.data.user.id); + } +} + +docs { + Creates a dashboard user and returns a bearer token. The token is auto-saved to the + `token` variable so every other request in this collection can reuse it via + `Authorization: Bearer {{token}}`. + + Re-run this any time you need a fresh user — each run generates a unique email. +} diff --git a/api-tests/Payment Links/Create Payment Link.bru b/api-tests/Payment Links/Create Payment Link.bru new file mode 100644 index 0000000..5360687 --- /dev/null +++ b/api-tests/Payment Links/Create Payment Link.bru @@ -0,0 +1,42 @@ +meta { + name: Create Payment Link + type: http + seq: 1 +} + +post { + url: {{base_url}}/v1/wallets/{{wallet_id}}/payment-links + body: json + auth: none +} + +headers { + authorization: Bearer {{token}} +} + +body:json { + { + "name": "Test payment link", + "description": "Created from Bruno", + "amount_usdc_stroops": 10000000, + "redirect_url": "https://example.com/thank-you" + } +} + +script:post-response { + if (res.body?.data?.slug) { + bru.setVar("link_id", res.body.data.id); + bru.setVar("link_slug", res.body.data.slug); + bru.setVar("checkout_url", res.body.data.url); + } +} + +docs { + amount_usdc_stroops is optional — omit it for a flexible-amount link the payer fills in. + redirect_url is optional too — where the payer's browser goes after a confirmed payment. + + The response's `url` field is the real hosted checkout link — open checkout_url in a browser + after running this to see the actual pay page. It's built from PUBLIC_APP_URL on the server, + so if it ever shows localhost in production, that env var isn't set correctly on the backend + host. +} diff --git a/api-tests/Payment Links/Deactivate Payment Link.bru b/api-tests/Payment Links/Deactivate Payment Link.bru new file mode 100644 index 0000000..10a86e4 --- /dev/null +++ b/api-tests/Payment Links/Deactivate Payment Link.bru @@ -0,0 +1,25 @@ +meta { + name: Deactivate Payment Link + type: http + seq: 4 +} + +put { + url: {{base_url}}/v1/wallets/{{wallet_id}}/payment-links/{{link_id}} + body: json + auth: none +} + +headers { + authorization: Bearer {{token}} +} + +body:json { + { + "active": false + } +} + +docs { + Set active: true to reactivate. An inactive link's public page (GET /v1/pay/:slug) 404s. +} diff --git a/api-tests/Payment Links/Get Payment Link.bru b/api-tests/Payment Links/Get Payment Link.bru new file mode 100644 index 0000000..4f2629f --- /dev/null +++ b/api-tests/Payment Links/Get Payment Link.bru @@ -0,0 +1,18 @@ +meta { + name: Get Payment Link + type: http + seq: 3 +} + +get { + url: {{base_url}}/v1/wallets/{{wallet_id}}/payment-links/{{link_id}} + auth: none +} + +headers { + authorization: Bearer {{token}} +} + +docs { + link_id is auto-saved by Create Payment Link. +} diff --git a/api-tests/Payment Links/List Payment Links.bru b/api-tests/Payment Links/List Payment Links.bru new file mode 100644 index 0000000..c226f21 --- /dev/null +++ b/api-tests/Payment Links/List Payment Links.bru @@ -0,0 +1,14 @@ +meta { + name: List Payment Links + type: http + seq: 2 +} + +get { + url: {{base_url}}/v1/wallets/{{wallet_id}}/payment-links + auth: none +} + +headers { + authorization: Bearer {{token}} +} diff --git a/api-tests/Payment Links/List Payments (owner).bru b/api-tests/Payment Links/List Payments (owner).bru new file mode 100644 index 0000000..78a1436 --- /dev/null +++ b/api-tests/Payment Links/List Payments (owner).bru @@ -0,0 +1,19 @@ +meta { + name: List Payments (owner) + type: http + seq: 5 +} + +get { + url: {{base_url}}/v1/wallets/{{wallet_id}}/payment-links/{{link_id}}/payments + auth: none +} + +headers { + authorization: Bearer {{token}} +} + +docs { + Owner-only: includes payer name/email, unlike anything on the public side. Includes pending + intents too, not just confirmed payments, so you can see abandoned checkouts. +} diff --git a/api-tests/Payment Links/Public - Create Intent.bru b/api-tests/Payment Links/Public - Create Intent.bru new file mode 100644 index 0000000..0f19489 --- /dev/null +++ b/api-tests/Payment Links/Public - Create Intent.bru @@ -0,0 +1,30 @@ +meta { + name: Public - Create Intent + type: http + seq: 7 +} + +post { + url: {{base_url}}/v1/pay/{{link_slug}}/intent + body: json + auth: none +} + +body:json { + { + "payer_name": "Jane Doe", + "payer_email": "jane@example.com" + } +} + +script:post-response { + if (res.body?.data?.payment_id) { + bru.setVar("payment_id", res.body.data.payment_id); + } +} + +docs { + No auth, rate-limited by IP (5/min). Allocates a dedicated address for THIS payment — two + concurrent payers on the same link get different addresses, so a deposit can only ever match + one of them. amount_usdc_stroops is required here only if the link itself is flexible-amount. +} diff --git a/api-tests/Payment Links/Public - Get Link.bru b/api-tests/Payment Links/Public - Get Link.bru new file mode 100644 index 0000000..d449ca2 --- /dev/null +++ b/api-tests/Payment Links/Public - Get Link.bru @@ -0,0 +1,15 @@ +meta { + name: Public - Get Link + type: http + seq: 6 +} + +get { + url: {{base_url}}/v1/pay/{{link_slug}} + auth: none +} + +docs { + No auth — this is what the hosted checkout page calls first. Returns the link's public + details plus the deposit address to send USDC to. +} diff --git a/api-tests/Payment Links/Public - Get Payment Status.bru b/api-tests/Payment Links/Public - Get Payment Status.bru new file mode 100644 index 0000000..96b7f98 --- /dev/null +++ b/api-tests/Payment Links/Public - Get Payment Status.bru @@ -0,0 +1,16 @@ +meta { + name: Public - Get Payment Status + type: http + seq: 8 +} + +get { + url: {{base_url}}/v1/pay/{{link_slug}}/payments/{{payment_id}} + auth: none +} + +docs { + No auth. status is one of pending | confirmed | expired | underpaid | overpaid. The pay page + polls this every ~3s while waiting. expected_usdc_stroops/received_usdc_stroops let you show + a mismatch banner without a second request. +} diff --git a/api-tests/Payment Links/Public - Get Signing Info.bru b/api-tests/Payment Links/Public - Get Signing Info.bru new file mode 100644 index 0000000..a1947e9 --- /dev/null +++ b/api-tests/Payment Links/Public - Get Signing Info.bru @@ -0,0 +1,19 @@ +meta { + name: Public - Get Signing Info + type: http + seq: 9 +} + +get { + url: {{base_url}}/v1/pay/{{link_slug}}/signing-info?account={{payer_account}} + auth: none +} + +docs { + No auth. account should be the PAYER's own Stellar address (e.g. from Freighter) — this + returns THAT account's current sequence number, network passphrase, and base fee, everything + needed to build a transaction client-side without hitting Horizon directly. + + Set the payer_account variable to a real G... address to try this (e.g. the one printed by + sign-challenge.js, once funded). +} diff --git a/api-tests/Payment Links/Public - Submit Signed.bru b/api-tests/Payment Links/Public - Submit Signed.bru new file mode 100644 index 0000000..4a423fb --- /dev/null +++ b/api-tests/Payment Links/Public - Submit Signed.bru @@ -0,0 +1,25 @@ +meta { + name: Public - Submit Signed + type: http + seq: 10 +} + +post { + url: {{base_url}}/v1/pay/{{link_slug}}/submit-signed + body: json + auth: none +} + +body:json { + { + "transaction_xdr": "paste a base64 client-signed TransactionEnvelope", + "payment_id": "{{payment_id}}" + } +} + +docs { + No auth. This can't be filled in from Bruno alone — the transaction has to be built (using + Public - Get Signing Info's response) and signed with the PAYER's own secret key first, which + needs a Stellar SDK (this is exactly what the hosted checkout page's Freighter flow does in + the browser). Included here for reference / to replay a captured request while debugging. +} diff --git a/api-tests/README.md b/api-tests/README.md new file mode 100644 index 0000000..8a91bd9 --- /dev/null +++ b/api-tests/README.md @@ -0,0 +1,46 @@ +# Octo API — Bruno collection + +Manual + repeatable testing for every route in the API. Free, open-source, no account needed: +https://www.usebruno.com + +## Setup + +1. Install Bruno (desktop app, or `npm i -g @usebruno/cli` for the `bru` CLI). +2. Open this `api-tests/` folder as a collection in Bruno. +3. Pick an environment top-right: **Local** (`http://localhost:8080`, needs the backend running + with `cargo run -p octo-server`) or **Production** (the live Render deploy). + +## Suggested run order + +1. **Auth → Signup** — creates a user, auto-saves `token`. +2. **Wallets → Get Ownership Challenge** — then run + `node api-tests/scripts/sign-challenge.js ""` (see that script's own README below) + to get a signed body, paste it into **Wallets → Create Wallet**, run it. Auto-saves + `wallet_id`. +3. From there every other request under Wallets/Addresses/Payment Links/Webhooks/Sponsorship/ + Whitelist just works — they all read `{{token}}` and `{{wallet_id}}`. +4. **Payment Links → Create Payment Link** auto-saves `link_slug`/`checkout_url`/`link_id`. + Open `checkout_url` in a browser to see the real hosted pay page. +5. **Payment Links → Public - ...** requests exercise the same flow a real payer's browser + would, with no auth — this is what a developer integrating checkout actually calls. + +## Why some requests can't just be "run" + +`Create Wallet` and `Public - Submit Signed` both require an ed25519 signature made with a +Stellar secret key Octo never sees (that's the point — it's non-custodial). Bruno has no +built-in Stellar signer, so: + +- `api-tests/scripts/sign-challenge.js` — run `npm install` once in `api-tests/scripts/`, then + `node sign-challenge.js ""` to generate a keypair, sign it, and print a ready body + for Create Wallet. +- `Public - Submit Signed` is documented for reference; actually driving it means building + + signing a transaction with a Stellar SDK, which is exactly what the hosted checkout page's + Freighter integration already does in the browser. + +## What "easy to integrate" looks like + +The **Payment Links** folder is the fastest way to answer "could a developer actually build a +checkout with this": create a link with an API key (no dashboard login needed — +`Generate API Key` under Wallets), get back a real `url`, and everything under `Public - *` +is what fires behind that URL with zero auth. See `/docs/checkout` on the frontend for the +narrative version of this same flow. diff --git a/api-tests/Sponsorship/Get Config.bru b/api-tests/Sponsorship/Get Config.bru new file mode 100644 index 0000000..4efdfc5 --- /dev/null +++ b/api-tests/Sponsorship/Get Config.bru @@ -0,0 +1,14 @@ +meta { + name: Get Config + type: http + seq: 1 +} + +get { + url: {{base_url}}/v1/wallets/{{wallet_id}}/sponsorship + auth: none +} + +headers { + authorization: Bearer {{token}} +} diff --git a/api-tests/Sponsorship/Update Config.bru b/api-tests/Sponsorship/Update Config.bru new file mode 100644 index 0000000..dfc0cee --- /dev/null +++ b/api-tests/Sponsorship/Update Config.bru @@ -0,0 +1,29 @@ +meta { + name: Update Config + type: http + seq: 2 +} + +put { + url: {{base_url}}/v1/wallets/{{wallet_id}}/sponsorship + body: json + auth: none +} + +headers { + authorization: Bearer {{token}} +} + +body:json { + { + "enabled": true, + "per_tx_fee_cap_stroops": 1000000, + "daily_budget_stroops": 50000000 + } +} + +docs { + Sponsoring lets your users transact on Stellar without holding XLM for fees — this wallet's + gas tank pays the fee-bump instead. Requires the gas tank to be provisioned first + (POST /v1/wallets/:id/gas-tank). +} diff --git a/api-tests/Wallets/Create Wallet.bru b/api-tests/Wallets/Create Wallet.bru new file mode 100644 index 0000000..934ef8d --- /dev/null +++ b/api-tests/Wallets/Create Wallet.bru @@ -0,0 +1,38 @@ +meta { + name: Create Wallet + type: http + seq: 2 +} + +post { + url: {{base_url}}/v1/wallets + body: json + auth: none +} + +headers { + authorization: Bearer {{token}} +} + +body:json { + { + "public_key": "paste-from-sign-challenge.js", + "challenge": "paste-from-Get-Ownership-Challenge", + "signature": "paste-from-sign-challenge.js", + "label": "test wallet" + } +} + +script:post-response { + if (res.body?.data?.id) { + bru.setVar("wallet_id", res.body.data.id); + } +} + +docs { + Registers a non-custodial wallet: the server never sees a private key, only the public + account plus proof (the signed challenge) that you control it. See Get Ownership Challenge + and api-tests/scripts/sign-challenge.js for how to fill this body in. + + On success, wallet_id is auto-saved for every other Wallets/Addresses/Payment Links request. +} diff --git a/api-tests/Wallets/Generate API Key.bru b/api-tests/Wallets/Generate API Key.bru new file mode 100644 index 0000000..38a99d8 --- /dev/null +++ b/api-tests/Wallets/Generate API Key.bru @@ -0,0 +1,26 @@ +meta { + name: Generate API Key + type: http + seq: 7 +} + +post { + url: {{base_url}}/v1/wallets/{{wallet_id}}/api-key + auth: none +} + +headers { + authorization: Bearer {{token}} +} + +script:post-response { + if (res.body?.data?.api_key) { + bru.setVar("api_key", res.body.data.api_key); + } +} + +docs { + Generates (or regenerates, invalidating the previous one) this wallet's API key. Shown once + — save it. Auto-saved to api_key, which is what an integrating merchant's backend would use + instead of a dashboard JWT for server-to-server calls (e.g. creating payment links). +} diff --git a/api-tests/Wallets/Get Balances.bru b/api-tests/Wallets/Get Balances.bru new file mode 100644 index 0000000..eb5b95a --- /dev/null +++ b/api-tests/Wallets/Get Balances.bru @@ -0,0 +1,19 @@ +meta { + name: Get Balances + type: http + seq: 5 +} + +get { + url: {{base_url}}/v1/wallets/{{wallet_id}}/balances + auth: none +} + +headers { + authorization: Bearer {{token}} +} + +docs { + Live balances straight from Horizon. A freshly created testnet wallet should show a small + XLM balance from friendbot funding. +} diff --git a/api-tests/Wallets/Get Ownership Challenge.bru b/api-tests/Wallets/Get Ownership Challenge.bru new file mode 100644 index 0000000..ef44cb9 --- /dev/null +++ b/api-tests/Wallets/Get Ownership Challenge.bru @@ -0,0 +1,33 @@ +meta { + name: Get Ownership Challenge + type: http + seq: 1 +} + +get { + url: {{base_url}}/v1/wallets/challenge + auth: none +} + +headers { + authorization: Bearer {{token}} +} + +script:post-response { + if (res.body?.data?.challenge) { + bru.setVar("challenge", res.body.data.challenge); + } +} + +docs { + Step 1 of registering a wallet: fetch a short-lived, user-bound challenge string. You then + sign it with the Stellar keypair's own secret key (ed25519) and send both the challenge and + the signature to Create Wallet, proving you control the private key for that public account. + + Bruno has no built-in ed25519 signer, so this collection can't complete a real Create Wallet + call on its own. Easiest paths to get a real wallet_id for the rest of this collection: + 1. Create one through the dashboard UI (it does the signing client-side), then copy its id + from the URL or the wallets list response. + 2. Or run `node api-tests/scripts/sign-challenge.js` (see that folder) which takes this + challenge and a generated keypair and prints a ready-to-paste Create Wallet body. +} diff --git a/api-tests/Wallets/Get Wallet.bru b/api-tests/Wallets/Get Wallet.bru new file mode 100644 index 0000000..973fd20 --- /dev/null +++ b/api-tests/Wallets/Get Wallet.bru @@ -0,0 +1,14 @@ +meta { + name: Get Wallet + type: http + seq: 4 +} + +get { + url: {{base_url}}/v1/wallets/{{wallet_id}} + auth: none +} + +headers { + authorization: Bearer {{token}} +} diff --git a/api-tests/Wallets/List Transactions.bru b/api-tests/Wallets/List Transactions.bru new file mode 100644 index 0000000..4b0e9e6 --- /dev/null +++ b/api-tests/Wallets/List Transactions.bru @@ -0,0 +1,14 @@ +meta { + name: List Transactions + type: http + seq: 6 +} + +get { + url: {{base_url}}/v1/wallets/{{wallet_id}}/transactions + auth: none +} + +headers { + authorization: Bearer {{token}} +} diff --git a/api-tests/Wallets/List Wallets.bru b/api-tests/Wallets/List Wallets.bru new file mode 100644 index 0000000..5b65568 --- /dev/null +++ b/api-tests/Wallets/List Wallets.bru @@ -0,0 +1,19 @@ +meta { + name: List Wallets + type: http + seq: 3 +} + +get { + url: {{base_url}}/v1/wallets + auth: none +} + +headers { + authorization: Bearer {{token}} +} + +docs { + Cursor-paginated. Response shape is {data: [...], next_cursor}; pass ?before= for + the next page. +} diff --git a/api-tests/Webhooks/Create Webhook.bru b/api-tests/Webhooks/Create Webhook.bru new file mode 100644 index 0000000..597ac78 --- /dev/null +++ b/api-tests/Webhooks/Create Webhook.bru @@ -0,0 +1,37 @@ +meta { + name: Create Webhook + type: http + seq: 1 +} + +post { + url: {{base_url}}/v1/wallets/{{wallet_id}}/webhooks + body: json + auth: none +} + +headers { + authorization: Bearer {{token}} +} + +body:json { + { + "url": "https://webhook.site/replace-with-your-own-uuid" + } +} + +script:post-response { + if (res.body?.data?.id) { + bru.setVar("webhook_id", res.body.data.id); + } +} + +docs { + url must be a public http(s) endpoint — loopback/private addresses are rejected. Response + includes a signing secret, shown once: save it to verify deliveries (see docs/webhooks in the + frontend repo for the HMAC verification recipe). + + Get a free disposable inspector URL at https://webhook.site to see real deliveries land. + Events fired: deposit.created, payment_link.paid, payment_link.mismatched, + payment_link.expired, transaction.sponsored. +} diff --git a/api-tests/Webhooks/Delete Webhook.bru b/api-tests/Webhooks/Delete Webhook.bru new file mode 100644 index 0000000..bfff285 --- /dev/null +++ b/api-tests/Webhooks/Delete Webhook.bru @@ -0,0 +1,14 @@ +meta { + name: Delete Webhook + type: http + seq: 3 +} + +delete { + url: {{base_url}}/v1/wallets/{{wallet_id}}/webhooks/{{webhook_id}} + auth: none +} + +headers { + authorization: Bearer {{token}} +} diff --git a/api-tests/Webhooks/List Webhooks.bru b/api-tests/Webhooks/List Webhooks.bru new file mode 100644 index 0000000..bdb10da --- /dev/null +++ b/api-tests/Webhooks/List Webhooks.bru @@ -0,0 +1,14 @@ +meta { + name: List Webhooks + type: http + seq: 2 +} + +get { + url: {{base_url}}/v1/wallets/{{wallet_id}}/webhooks + auth: none +} + +headers { + authorization: Bearer {{token}} +} diff --git a/api-tests/Whitelist/Add Address.bru b/api-tests/Whitelist/Add Address.bru new file mode 100644 index 0000000..379a497 --- /dev/null +++ b/api-tests/Whitelist/Add Address.bru @@ -0,0 +1,27 @@ +meta { + name: Add Address + type: http + seq: 2 +} + +post { + url: {{base_url}}/v1/wallets/{{wallet_id}}/whitelist + body: json + auth: none +} + +headers { + authorization: Bearer {{token}} +} + +body:json { + { + "address": "GAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAWHF", + "label": "known-good destination" + } +} + +docs { + When the whitelist is enabled (PUT /v1/wallets/:id/whitelist/config), submit-signed rejects + any payment to a destination not on this list — an anti-fraud control. +} diff --git a/api-tests/Whitelist/Get Config.bru b/api-tests/Whitelist/Get Config.bru new file mode 100644 index 0000000..70b3e76 --- /dev/null +++ b/api-tests/Whitelist/Get Config.bru @@ -0,0 +1,14 @@ +meta { + name: Get Config + type: http + seq: 1 +} + +get { + url: {{base_url}}/v1/wallets/{{wallet_id}}/whitelist/config + auth: none +} + +headers { + authorization: Bearer {{token}} +} diff --git a/api-tests/Whitelist/List Addresses.bru b/api-tests/Whitelist/List Addresses.bru new file mode 100644 index 0000000..a8e5e3a --- /dev/null +++ b/api-tests/Whitelist/List Addresses.bru @@ -0,0 +1,14 @@ +meta { + name: List Addresses + type: http + seq: 3 +} + +get { + url: {{base_url}}/v1/wallets/{{wallet_id}}/whitelist + auth: none +} + +headers { + authorization: Bearer {{token}} +} diff --git a/api-tests/bruno.json b/api-tests/bruno.json new file mode 100644 index 0000000..e050f50 --- /dev/null +++ b/api-tests/bruno.json @@ -0,0 +1,6 @@ +{ + "version": "1", + "name": "Octo API", + "type": "collection", + "ignore": ["node_modules", ".git"] +} diff --git a/api-tests/environments/Local.bru b/api-tests/environments/Local.bru new file mode 100644 index 0000000..69a53d4 --- /dev/null +++ b/api-tests/environments/Local.bru @@ -0,0 +1,3 @@ +vars { + base_url: http://localhost:8080 +} diff --git a/api-tests/environments/Production.bru b/api-tests/environments/Production.bru new file mode 100644 index 0000000..1327221 --- /dev/null +++ b/api-tests/environments/Production.bru @@ -0,0 +1,3 @@ +vars { + base_url: https://octo-backend-ornz.onrender.com +} diff --git a/api-tests/scripts/.gitignore b/api-tests/scripts/.gitignore new file mode 100644 index 0000000..c2658d7 --- /dev/null +++ b/api-tests/scripts/.gitignore @@ -0,0 +1 @@ +node_modules/ diff --git a/api-tests/scripts/package-lock.json b/api-tests/scripts/package-lock.json new file mode 100644 index 0000000..6601997 --- /dev/null +++ b/api-tests/scripts/package-lock.json @@ -0,0 +1,560 @@ +{ + "name": "octo-api-test-scripts", + "lockfileVersion": 3, + "requires": true, + "packages": { + "": { + "name": "octo-api-test-scripts", + "dependencies": { + "@stellar/stellar-base": "^15.0.0" + } + }, + "node_modules/@noble/curves": { + "version": "1.9.7", + "resolved": "https://registry.npmjs.org/@noble/curves/-/curves-1.9.7.tgz", + "integrity": "sha512-gbKGcRUYIjA3/zCCNaWDciTMFI0dCkvou3TL8Zmy5Nc7sJ47a0jtOeZoTaMxkuqRo9cRhjOdZJXegxYE5FN/xw==", + "license": "MIT", + "dependencies": { + "@noble/hashes": "1.8.0" + }, + "engines": { + "node": "^14.21.3 || >=16" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + } + }, + "node_modules/@noble/hashes": { + "version": "1.8.0", + "resolved": "https://registry.npmjs.org/@noble/hashes/-/hashes-1.8.0.tgz", + "integrity": "sha512-jCs9ldd7NwzpgXDIf6P3+NrHh9/sD6CQdxHyjQI+h/6rDNo88ypBxxz45UDuZHz9r3tNz7N/VInSVoVdtXEI4A==", + "license": "MIT", + "engines": { + "node": "^14.21.3 || >=16" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + } + }, + "node_modules/@stellar/js-xdr": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/@stellar/js-xdr/-/js-xdr-4.0.0.tgz", + "integrity": "sha512-+NmNa7Tk5BI5XFdy/6xGTqAN4J9a9KgCrCGhj2uEUTCBhLkch0M+QbKzNH8zEnejWe0p8w+0q5hUVX6L3OzoVA==", + "license": "Apache-2.0", + "engines": { + "node": ">=20.0.0", + "pnpm": ">=9.0.0" + } + }, + "node_modules/@stellar/stellar-base": { + "version": "15.0.0", + "resolved": "https://registry.npmjs.org/@stellar/stellar-base/-/stellar-base-15.0.0.tgz", + "integrity": "sha512-XQhxUr9BYiEcFcgc4oWcCMR9QJCny/GmmGsuwPKf/ieIcOeb5149KLHYx9mJCA0ea8QbucR2/GzV58QbXOTxQA==", + "deprecated": "This package is now rolled into @stellar/stellar-sdk. Please use @stellar/stellar-sdk to continue receiving updates and support.", + "license": "Apache-2.0", + "dependencies": { + "@noble/curves": "^1.9.7", + "@stellar/js-xdr": "^4.0.0", + "base32.js": "^0.1.0", + "bignumber.js": "^9.3.1", + "buffer": "^6.0.3", + "sha.js": "^2.4.12" + }, + "engines": { + "node": ">=20.0.0" + } + }, + "node_modules/available-typed-arrays": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/available-typed-arrays/-/available-typed-arrays-1.0.7.tgz", + "integrity": "sha512-wvUjBtSGN7+7SjNpq/9M2Tg350UZD3q62IFZLbRAR1bSMlCo1ZaeW+BJ+D090e4hIIZLBcTDWe4Mh4jvUDajzQ==", + "license": "MIT", + "dependencies": { + "possible-typed-array-names": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/base32.js": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/base32.js/-/base32.js-0.1.0.tgz", + "integrity": "sha512-n3TkB02ixgBOhTvANakDb4xaMXnYUVkNoRFJjQflcqMQhyEKxEHdj3E6N8t8sUQ0mjH/3/JxzlXuz3ul/J90pQ==", + "license": "MIT", + "engines": { + "node": ">=0.12.0" + } + }, + "node_modules/base64-js": { + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz", + "integrity": "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT" + }, + "node_modules/bignumber.js": { + "version": "9.3.1", + "resolved": "https://registry.npmjs.org/bignumber.js/-/bignumber.js-9.3.1.tgz", + "integrity": "sha512-Ko0uX15oIUS7wJ3Rb30Fs6SkVbLmPBAKdlm7q9+ak9bbIeFf0MwuBsQV6z7+X768/cHsfg+WlysDWJcmthjsjQ==", + "license": "MIT", + "engines": { + "node": "*" + } + }, + "node_modules/buffer": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/buffer/-/buffer-6.0.3.tgz", + "integrity": "sha512-FTiCpNxtwiZZHEZbcbTIcZjERVICn9yq/pDFkTl95/AxzD1naBctN7YO68riM/gLSDY7sdrMby8hofADYuuqOA==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT", + "dependencies": { + "base64-js": "^1.3.1", + "ieee754": "^1.2.1" + } + }, + "node_modules/call-bind": { + "version": "1.0.9", + "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.9.tgz", + "integrity": "sha512-a/hy+pNsFUTR+Iz8TCJvXudKVLAnz/DyeSUo10I5yvFDQJBFU2s9uqQpoSrJlroHUKoKqzg+epxyP9lqFdzfBQ==", + "license": "MIT", + "dependencies": { + "call-bind-apply-helpers": "^1.0.2", + "es-define-property": "^1.0.1", + "get-intrinsic": "^1.3.0", + "set-function-length": "^1.2.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/call-bind-apply-helpers": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/call-bind-apply-helpers/-/call-bind-apply-helpers-1.0.2.tgz", + "integrity": "sha512-Sp1ablJ0ivDkSzjcaJdxEunN5/XvksFJ2sMBFfq6x0ryhQV/2b/KwFe21cMpmHtPOSij8K99/wSfoEuTObmuMQ==", + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0", + "function-bind": "^1.1.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/call-bound": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/call-bound/-/call-bound-1.0.4.tgz", + "integrity": "sha512-+ys997U96po4Kx/ABpBCqhA9EuxJaQWDQg7295H4hBphv3IZg0boBKuwYpt4YXp6MZ5AmZQnU/tyMTlRpaSejg==", + "license": "MIT", + "dependencies": { + "call-bind-apply-helpers": "^1.0.2", + "get-intrinsic": "^1.3.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/define-data-property": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/define-data-property/-/define-data-property-1.1.4.tgz", + "integrity": "sha512-rBMvIzlpA8v6E+SJZoo++HAYqsLrkg7MSfIinMPFhmkorw7X+dOXVJQs+QT69zGkzMyfDnIMN2Wid1+NbL3T+A==", + "license": "MIT", + "dependencies": { + "es-define-property": "^1.0.0", + "es-errors": "^1.3.0", + "gopd": "^1.0.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/dunder-proto": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/dunder-proto/-/dunder-proto-1.0.1.tgz", + "integrity": "sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A==", + "license": "MIT", + "dependencies": { + "call-bind-apply-helpers": "^1.0.1", + "es-errors": "^1.3.0", + "gopd": "^1.2.0" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-define-property": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/es-define-property/-/es-define-property-1.0.1.tgz", + "integrity": "sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g==", + "license": "MIT", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-errors": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/es-errors/-/es-errors-1.3.0.tgz", + "integrity": "sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==", + "license": "MIT", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-object-atoms": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/es-object-atoms/-/es-object-atoms-1.1.2.tgz", + "integrity": "sha512-HWcBoN6NileqtSydK2FqHbS/LoDd2pqrnQHLyJzBj4kOp/ky2MWMN694xOfkK8/SnUsW2DH7EfyVlydKCsm1Zw==", + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/for-each": { + "version": "0.3.5", + "resolved": "https://registry.npmjs.org/for-each/-/for-each-0.3.5.tgz", + "integrity": "sha512-dKx12eRCVIzqCxFGplyFKJMPvLEWgmNtUrpTiJIR5u97zEhRG8ySrtboPHZXx7daLxQVrl643cTzbab2tkQjxg==", + "license": "MIT", + "dependencies": { + "is-callable": "^1.2.7" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/function-bind": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz", + "integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==", + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/get-intrinsic": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.3.0.tgz", + "integrity": "sha512-9fSjSaos/fRIVIp+xSJlE6lfwhES7LNtKaCBIamHsjr2na1BiABJPo0mOjjz8GJDURarmCPGqaiVg5mfjb98CQ==", + "license": "MIT", + "dependencies": { + "call-bind-apply-helpers": "^1.0.2", + "es-define-property": "^1.0.1", + "es-errors": "^1.3.0", + "es-object-atoms": "^1.1.1", + "function-bind": "^1.1.2", + "get-proto": "^1.0.1", + "gopd": "^1.2.0", + "has-symbols": "^1.1.0", + "hasown": "^2.0.2", + "math-intrinsics": "^1.1.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/get-proto": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/get-proto/-/get-proto-1.0.1.tgz", + "integrity": "sha512-sTSfBjoXBp89JvIKIefqw7U2CCebsc74kiY6awiGogKtoSGbgjYE/G/+l9sF3MWFPNc9IcoOC4ODfKHfxFmp0g==", + "license": "MIT", + "dependencies": { + "dunder-proto": "^1.0.1", + "es-object-atoms": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/gopd": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.2.0.tgz", + "integrity": "sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg==", + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/has-property-descriptors": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/has-property-descriptors/-/has-property-descriptors-1.0.2.tgz", + "integrity": "sha512-55JNKuIW+vq4Ke1BjOTjM2YctQIvCT7GFzHwmfZPGo5wnrgkid0YQtnAleFSqumZm4az3n2BS+erby5ipJdgrg==", + "license": "MIT", + "dependencies": { + "es-define-property": "^1.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/has-symbols": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.1.0.tgz", + "integrity": "sha512-1cDNdwJ2Jaohmb3sg4OmKaMBwuC48sYni5HUw2DvsC8LjGTLK9h+eb1X6RyuOHe4hT0ULCW68iomhjUoKUqlPQ==", + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/has-tostringtag": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/has-tostringtag/-/has-tostringtag-1.0.2.tgz", + "integrity": "sha512-NqADB8VjPFLM2V0VvHUewwwsw0ZWBaIdgo+ieHtK3hasLz4qeCRjYcqfB6AQrBggRKppKF8L52/VqdVsO47Dlw==", + "license": "MIT", + "dependencies": { + "has-symbols": "^1.0.3" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/hasown": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.4.tgz", + "integrity": "sha512-T2UbfbBEF32wiepXIsMlTW9+dDYC6wMh/t/vYA4tuOMKqWz/n3vr1NFSxQiyP+zk2mXsoMA/i/7qV6LKut1t1A==", + "license": "MIT", + "dependencies": { + "function-bind": "^1.1.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/ieee754": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.2.1.tgz", + "integrity": "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "BSD-3-Clause" + }, + "node_modules/inherits": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", + "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", + "license": "ISC" + }, + "node_modules/is-callable": { + "version": "1.2.7", + "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.2.7.tgz", + "integrity": "sha512-1BC0BVFhS/p0qtw6enp8e+8OD0UrK0oFLztSjNzhcKA3WDuJxxAPXzPuPtKkjEY9UUoEWlX/8fgKeu2S8i9JTA==", + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-typed-array": { + "version": "1.1.15", + "resolved": "https://registry.npmjs.org/is-typed-array/-/is-typed-array-1.1.15.tgz", + "integrity": "sha512-p3EcsicXjit7SaskXHs1hA91QxgTw46Fv6EFKKGS5DRFLD8yKnohjF3hxoju94b/OcMZoQukzpPpBE9uLVKzgQ==", + "license": "MIT", + "dependencies": { + "which-typed-array": "^1.1.16" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/isarray": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-2.0.5.tgz", + "integrity": "sha512-xHjhDr3cNBK0BzdUJSPXZntQUx/mwMS5Rw4A7lPJ90XGAO6ISP/ePDNuo0vhqOZU+UD5JoodwCAAoZQd3FeAKw==", + "license": "MIT" + }, + "node_modules/math-intrinsics": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/math-intrinsics/-/math-intrinsics-1.1.0.tgz", + "integrity": "sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g==", + "license": "MIT", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/possible-typed-array-names": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/possible-typed-array-names/-/possible-typed-array-names-1.1.0.tgz", + "integrity": "sha512-/+5VFTchJDoVj3bhoqi6UeymcD00DAwb1nJwamzPvHEszJ4FpF6SNNbUbOS8yI56qHzdV8eK0qEfOSiodkTdxg==", + "license": "MIT", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/safe-buffer": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", + "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT" + }, + "node_modules/set-function-length": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/set-function-length/-/set-function-length-1.2.2.tgz", + "integrity": "sha512-pgRc4hJ4/sNjWCSS9AmnS40x3bNMDTknHgL5UaMBTMyJnU90EgWh1Rz+MC9eFu4BuN/UwZjKQuY/1v3rM7HMfg==", + "license": "MIT", + "dependencies": { + "define-data-property": "^1.1.4", + "es-errors": "^1.3.0", + "function-bind": "^1.1.2", + "get-intrinsic": "^1.2.4", + "gopd": "^1.0.1", + "has-property-descriptors": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/sha.js": { + "version": "2.4.12", + "resolved": "https://registry.npmjs.org/sha.js/-/sha.js-2.4.12.tgz", + "integrity": "sha512-8LzC5+bvI45BjpfXU8V5fdU2mfeKiQe1D1gIMn7XUlF3OTUrpdJpPPH4EMAnF0DsHHdSZqCdSss5qCmJKuiO3w==", + "license": "(MIT AND BSD-3-Clause)", + "dependencies": { + "inherits": "^2.0.4", + "safe-buffer": "^5.2.1", + "to-buffer": "^1.2.0" + }, + "bin": { + "sha.js": "bin.js" + }, + "engines": { + "node": ">= 0.10" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/to-buffer": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/to-buffer/-/to-buffer-1.2.2.tgz", + "integrity": "sha512-db0E3UJjcFhpDhAF4tLo03oli3pwl3dbnzXOUIlRKrp+ldk/VUxzpWYZENsw2SZiuBjHAk7DfB0VU7NKdpb6sw==", + "license": "MIT", + "dependencies": { + "isarray": "^2.0.5", + "safe-buffer": "^5.2.1", + "typed-array-buffer": "^1.0.3" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/typed-array-buffer": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/typed-array-buffer/-/typed-array-buffer-1.0.3.tgz", + "integrity": "sha512-nAYYwfY3qnzX30IkA6AQZjVbtK6duGontcQm1WSG1MD94YLqK0515GNApXkoxKOWMusVssAHWLh9SeaoefYFGw==", + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.3", + "es-errors": "^1.3.0", + "is-typed-array": "^1.1.14" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/which-typed-array": { + "version": "1.1.22", + "resolved": "https://registry.npmjs.org/which-typed-array/-/which-typed-array-1.1.22.tgz", + "integrity": "sha512-fvO4ExWMFsqyhG3AiPAObMuY1lxaqgYcxbc49CNdWDDECOJNgQyvsOWVwbZc+qf3rzRtxojBK+CMEv0Ld5CYpw==", + "license": "MIT", + "dependencies": { + "available-typed-arrays": "^1.0.7", + "call-bind": "^1.0.9", + "call-bound": "^1.0.4", + "for-each": "^0.3.5", + "get-proto": "^1.0.1", + "gopd": "^1.2.0", + "has-tostringtag": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + } + } +} diff --git a/api-tests/scripts/package.json b/api-tests/scripts/package.json new file mode 100644 index 0000000..b017c37 --- /dev/null +++ b/api-tests/scripts/package.json @@ -0,0 +1,8 @@ +{ + "name": "octo-api-test-scripts", + "private": true, + "type": "module", + "dependencies": { + "@stellar/stellar-base": "^15.0.0" + } +} diff --git a/api-tests/scripts/sign-challenge.js b/api-tests/scripts/sign-challenge.js new file mode 100644 index 0000000..b7e26b8 --- /dev/null +++ b/api-tests/scripts/sign-challenge.js @@ -0,0 +1,38 @@ +#!/usr/bin/env node +// Generates a Stellar keypair, signs an ownership challenge, and prints a ready-to-paste +// Create Wallet request body. Run: node sign-challenge.js "" +// +// Setup: npm install (in this scripts/ directory) once, first. + +import { Keypair } from "@stellar/stellar-base"; + +const challenge = process.argv[2]; +if (!challenge) { + console.error('Usage: node sign-challenge.js ""'); + console.error( + "Get from the Get Ownership Challenge request's response (data.challenge).", + ); + process.exit(1); +} + +const kp = Keypair.random(); +const signature = kp.sign(Buffer.from(challenge)).toString("base64"); + +console.log("Public key (save this — you'll need it to sign future transactions too):"); +console.log(" " + kp.publicKey()); +console.log("Secret key (KEEP PRIVATE — Octo is non-custodial, it never sees this):"); +console.log(" " + kp.secret()); +console.log(); +console.log("Paste this as the Create Wallet request body:"); +console.log( + JSON.stringify( + { + public_key: kp.publicKey(), + challenge, + signature, + label: "test wallet", + }, + null, + 2, + ), +);