black.box Unzoner API service using Flask on Python
This block implements black.box Unzoner API backend, which provides a common interface for all other services.
- add the latest unzoner-api block to your balenaCloud fleet composition (e.g.
amd64
)
version: '2.4'
services:
unzoner-api:
# https://www.balena.io/docs/learn/develop/blocks/#using-your-block-in-other-projects
image: bh.cr/belodetek/unzoner-api-amd64
restart: unless-stopped
ports:
# it is assumed there is a load-baancer/proxy fronting the API
- "80:80/tcp"
# https://www.balena.io/docs/reference/supervisor/docker-compose/#labels
labels:
io.balena.update.strategy: download-then-kill
unzoner-dns:
...
set fleet environment variables
name | description | example |
---|---|---|
API_HOST | your Unzoner API URL | (e.g.) https://api.acme.com |
API_SECRET | shared secret | (e.g.) openssl rand -hex 16 |
API_VERSION | your Unzoner API version | (e.g.) 1.0 |
BITCOIN_PAYMENT_WALLET_XPUBKEY | public key of the wallet for incoming payments | xpub format |
BLOCKCYPHER_API_TOKEN | API token | link |
BLOCKCYPHER_COIN_SYMBOL | Bitcoin channel | btc , btc-testnet |
BLOCKCYPHER_WALLET_NAME | name of the wallet for incoming payments | link |
BLOCKCYPHER_WEBHOOK_TOKEN | WebHook API token | link |
GEOIP_API_KEY | API key | link |
GITHUB_ACCESS_TOKEN | GitHub PAT with access to private repositories | link |
PAYPAL_BASE_URL | PayPal API | link |
PAYPAL_BILLING_PLAN_REGULAR | PayPal regular billing plan ID | see, create_pp_billing_plan |
PAYPAL_BILLING_PLAN_TRIAL | PayPal trial billing plan ID | see, create_pp_billing_plan |
PAYPAL_CLIENT_ID | PayPal client ID | link |
PAYPAL_CLIENT_SECRET | PayPal secret | link |
PAYPAL_WEBHOOK_ID | PayPal WebHook ID | link |
RESIN_APP_ID | balena fleet IDs | comma separated list of fleet IDs |
RESN_PASSWORD | balenaCloud password | link |
RESN_USERNAME | balenaCloud username | link |
SMTP_FROM | Your Gmail email address | (e.g) [email protected] |
SMTP_PASSWORD | Google app password | link |
SMTP_RCPT_TO | Your Gmail email address | (e.g) [email protected] |
SMTP_USERNAME | Your Gmail email address | (e.g) [email protected] |
include convenience function to escape unsafe characters in URLs
api_url="${API_HOST}/api/v${API_VERSION}"
curl "${api_url}/ping"
function urlencode() {
local encoded="$1"
encoded=$(echo ${encoded} | sed 's/%/%25/g')
encoded=$(echo ${encoded} | sed 's/ /%20/g')
encoded=$(echo ${encoded} | sed 's/!/%21/g')
encoded=$(echo ${encoded} | sed 's/#/%23/g')
encoded=$(echo ${encoded} | sed 's/\$/%24/g')
encoded=$(echo ${encoded} | sed 's/&/%26/g')
encoded=$(echo ${encoded} | sed 's/(/%28/g')
encoded=$(echo ${encoded} | sed 's/)/%29/g')
encoded=$(echo ${encoded} | sed 's/*/%2A/g')
encoded=$(echo ${encoded} | sed 's/+/%2B/g')
encoded=$(echo ${encoded} | sed 's#\/#%2F#g')
encoded=$(echo ${encoded} | sed 's/:/%3A/g')
encoded=$(echo ${encoded} | sed 's/;/%3B/g')
encoded=$(echo ${encoded} | sed 's/</%3C/g')
encoded=$(echo ${encoded} | sed 's/=/%3D/g')
encoded=$(echo ${encoded} | sed 's/>/%3E/g')
encoded=$(echo ${encoded} | sed 's/?/%3F/g')
encoded=$(echo ${encoded} | sed 's/@/%40/g')
encoded=$(echo ${encoded} | sed 's/\[/%5B/g')
encoded=$(echo ${encoded} | sed 's/\\/%5C/g')
encoded=$(echo ${encoded} | sed 's/]/%5D/g')
encoded=$(echo ${encoded} | sed 's/\^/%5E/g')
encoded=$(echo ${encoded} | sed 's/\`/%60/g')
encoded=$(echo ${encoded} | sed 's/{/%7B/g')
encoded=$(echo ${encoded} | sed 's/|/%7C/g')
encoded=$(echo ${encoded} | sed 's/}/%7D/g')
encoded=$(echo ${encoded} | sed 's/~/%7E/g')
echo "${encoded}"
}
most of the calls implementing required PayPal API functionality
curl "${api_url}/paypal/billing-agreements/{{ balena_device_uuid|JWT.payload }}/create/{{ billing_type }}" \
-H "X-Auth-Token: ${AUTH_TOKEN}"
curl "${api_url}/paypal/billing-agreements/execute?token={{ paypal_token }}"
curl "${api_url}/paypal/billing-agreements/{{ billing_agreement }}" \
-H "X-Auth-Token: ${AUTH_TOKEN}"
curl "${api_url}/paypal/billing-agreements/{{ billing_agreement }}/confirm" \
-H "X-Auth-Token: ${AUTH_TOKEN}"
curl "${api_url}/paypal/billing-plans" \
-H "X-Auth-Token: ${AUTH_TOKEN}"
curl "${api_url}/paypal/billing-plans/{{ billing_plan }}" \
-H "X-Auth-Token: ${AUTH_TOKEN}"
curl "${api_url}/paypal/billing-plans/create/{{ billing_type }}" \
-H "X-Auth-Token: ${AUTH_TOKEN}"
curl "${api_url}/paypal/billing-plans/{{ billing_plan }}/activate" \
-H "X-Auth-Token: ${AUTH_TOKEN}"
most of the calls implementing core functionality
curl "${api_url}/alpha/US/asns/common" \
-H "X-Auth-Token: ${AUTH_TOKEN}"
curl "${api_url}/alpha/US/domains/common,netflix" \
-H "X-Auth-Token: ${AUTH_TOKEN}"
curl "${api_url}/alpha/US/services/default/1" \
-H "X-Auth-Token: ${AUTH_TOKEN}"
curl "${api_url}/alpha/US/services/default/0" \
-H "X-Auth-Token: ${AUTH_TOKEN}"
curl "${api_url}/countries/all" \
-H "X-Auth-Token: ${AUTH_TOKEN}" | jq -r
curl "${api_url}/countries/available" \
-H "X-Auth-Token: ${AUTH_TOKEN}" | jq -r
curl -I "${api_url}/countries/available/flags.png"
country="$(urlencode 'United Kingdom')"
curl "${api_url}/country/${country}" \
-H "X-Auth-Token: ${AUTH_TOKEN}"
for af in 4 6; do
curl "${api_url}/node/${af}/country/${country}" \
-H "X-Auth-Token: ${AUTH_TOKEN}"
done
for af in 4 6; do
curl "${api_url}/node/${af}/guid/{{ balena_device_uuid }}" \
-H "X-Auth-Token: ${AUTH_TOKEN}"
done
for af in 4 6; do
ip="$(curl -${af} ifconfig.co/ip)"
curl "${api_url}/node/${af}/country/${country}/geo/${ip}" \
-H "X-Auth-Token: ${AUTH_TOKEN}"
done
af=4
type=4
balena_device_uuid=$(uuid | sed 's/-//g')
json=$(curl -s mgmt.${DNS_DOMAIN}/json)
country=$(echo ${json} | jq -r .country)
city=$(echo ${json} | jq -r .city)
ip=$(echo ${json} | jq -r .ip)
curl -X PUT "${api_url}/device/${type}/${balena_device_uuid}/${af}" \
-H "X-Auth-Token: ${AUTH_TOKEN}" \
-H 'Content-Type: application/json' \
-d "{\"weight\":1,\"cipher\":null,\"auth\":null,\"upnp\":0,\"hostapd\":0,\"ip\":\"${ip}\",\"country\":\"${country}\",\"city\":\"${city}\",\"conns\":0,\"weight\":1,\"bytesin\":0,\"bytesout\":0,\"status\":1}"
for af in 4 6; do
curl "${api_url}/device/${TYPE}/{{ balena_device_uuid }}/${af}" \
-H "X-Auth-Token: ${AUTH_TOKEN}"
done
for af in 4 6; do
for dt in 1 2 3 4 5; do
curl "${api_url}/device/${dt}/${balena_device_uuid}/${af}/stats" \
-H "X-Auth-Token: ${AUTH_TOKEN}"
done
done
curl -X PUT "${api_url}/device/{{ balena_device_uuid }}/env" \
-H 'Content-type: application/json' \
-H "X-Auth-Token: ${AUTH_TOKEN}" \
-d "{\"env_var_name\": \"${env_var_name}\", \"value\": \"${env_var_value}\"}"
curl "${api_url}/device/{{ balena_device_uuid }}/env" \
-H "X-Auth-Token: ${AUTH_TOKEN}"
curl -X DELETE "${api_url}/env/${env_var_id}" \
-H "X-Auth-Token: ${AUTH_TOKEN}"
curl -X PATCH "${api_url}/env/${env_var_id}" \
-H 'Content-type: application/json' \
-H "X-Auth-Token: ${AUTH_TOKEN}" \
-d "{\"value\": \"${env_var_value}\"}"
curl "${api_url}/device/{{ balena_device_uuid }}" \
-H "X-Auth-Token: ${AUTH_TOKEN}"
see, application.py and bitcoin.py
API calls implementing VPN providers database
curl "${api_url}/vpnprovider/groups"
curl "${api_url}/vpnproviders"
curl "${api_url}/vpnproviders/group/{{ vpn_provider_group }}"
curl "${api_url}/vpnprovider/{{ vpn_provider }}/groups"
curl "${api_url}/vpnprovider/{{ vpn_provider }}/group/$(urlencode "{{ vpn_location_group }}")/locations"
NordVPN, IPVanish and PIA are the only supported providers currently
curl "${api_url}/vpnprovider/{{ vpn_provider }}/group/$(urlencode "{{ vpn_location_group }}")/locations/load"
NordVPN, IPVanish and PIA are the only supported providers currently
curl "${api_url}/vpnprovider/{{ vpn_provider }}/group/$(urlencode "{{ vpn_location_group }}")/locations/geo/lat/{{ lattitude }}/lon/{{ longitude }}"
curl "${api_url}/vpnprovider/{{ vpn_provider }}/usercert"
curl "${api_url}/vpnprovider/{{ vpn_provider }}/group/$(urlencode "{{ vpn_location_group }}")/name/$(urlencode "{{ vpn_location_group }}")/profile"
NordVPN
,IPVanish
andPIA
are currently supported
curl "${api_url}/vpnprovider/{{ vpn_provider }}/update" \
-H "X-Auth-Token: ${AUTH_TOKEN}"
⏳ DD-WRT is currently private...
curl "${api_url}/ddwrt/group/{{ vpn_provider_group }}/provider/{{ vpn_provider }}/install"
To install on the router, pipe output to sh (e.g.
| sh
).
curl "${API_HOST}/ddwrt"
curl "${api_url}/ddwrt/download" \
-o ./ddwrt-mypage.tar.gz
curl "${api_url}/ddwrt/version"
calls implementing dashboard functionality, such as
speedtest
andIOtest
curl "${api_url}/tests/sessions" \
-H "X-Auth-Token: ${AUTH_TOKEN}"
curl "${api_url}/tests/errors" \
-H "X-Auth-Token: ${AUTH_TOKEN}"
curl "${api_url}/tests/screenshots" \
-H "X-Auth-Token: ${AUTH_TOKEN}"
curl "${api_url}/tests/nflx_video_diags" \
-H "X-Auth-Token: ${AUTH_TOKEN}"
curl "${api_url}/screenshot/US" \
-H "X-Auth-Token: ${AUTH_TOKEN}"
curl "${api_url}/screenshot/tags/10" \
-H "X-Auth-Token: ${AUTH_TOKEN}"
curl -I "${api_url}/speedtest/{{ balena_device_uuid }}" \
-H "X-Auth-Token: ${AUTH_TOKEN}"
curl -X PATCH "${api_url}/speedtest/{{ balena_device_uuid }}" \
-H 'Content-type: application/json' \
-H "X-Auth-Token: ${AUTH_TOKEN}" \
-d "{\"status\":0,\"up\":\"0.0-12.6 sec 4.25 MBytes 2.84 Mbits/sec\",\"down\":\"0.0-11.1 sec 9.88 MBytes 7.46 Mbits/sec\"}"
curl -X PUT "${api_url}/iotest/{{ test_id }}/guid/{{ balena_device_uuid }}"\
-H "X-Auth-Token: ${AUTH_TOKEN}"
curl "${api_url}/iotest/queue/{{ balena_device_uuid }}"\
-H "X-Auth-Token: ${AUTH_TOKEN}"
curl -X PATCH "${api_url}/iotest/{{ balena_device_uuid }}" \
-H 'Content-type: application/json' \
-H "X-Auth-Token: ${AUTH_TOKEN}" \
-d "{\"status\":0,\"result\":\"419430400 bytes (419 MB, 400 MiB) copied, 46.5299 s, 9.0 MB/s\",\"test\":{{ test_id }}}"
curl "${api_url}/iotest/{{ test_id }}/guid/{{ balena_device_uuid }}" \
-H "X-Auth-Token: ${AUTH_TOKEN}"