Skip to content

Latest commit

 

History

2 Commits

Folders and files

NameName
Last commit message
Last commit date
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Bruncsoft Connect

A self-hosted integration hub. Run it on your own server and connect as many of your sites as you like through a single local API.

  • Nothing runs on anyone else's server. No accounts, no cloud, no phone-home. Your hub issues the keys and your hub verifies them.
  • Every site gets its own key. init mints the admin key (bsc_) that runs the install; registering a site mints a site key (bscs_) for that site alone. A site key can push into a connection and read the result — it cannot create a site, define a connection, or mint another key. So a leaked key names exactly one site, is revoked on its own, and cannot be used to widen the breach.
  • Keys are entropy, not registry. 512 bits of CSPRNG randomness each, stored only as a SHA-256 hash, shown once, with a checksum that rejects typos offline.
  • One engine, your workflows. A connection is a list of steps — fetch (call any of your sites/APIs), transform (reshape data), when (conditional gate). Push data into a connection and read the result back out.

Install

cd packages/connect
npm install

(Or, once published, npm install -g @bruncsoft/connect.)

Quick start

# 1. Mint the admin key (printed once — store it now)
node bin/connect.js init

# 2. Run the hub (defaults to 127.0.0.1:8787)
node bin/connect.js start --port 8787

Management uses the admin key:

KEY=bsc_...                       # the admin key from `init`
H="Authorization: Bearer $KEY"

# register a site — the response carries THAT SITE'S own key, shown once
curl -X POST localhost:8787/sites -H "$H" -H 'Content-Type: application/json' \
  -d '{"name":"My Shop","base_url":"https://shop.example.com"}'
# → { "ok": true, "slug": "my-shop", "key": "bscs_…", "note": "shown once…" }

# define a connection: forward only when the value changed
curl -X POST localhost:8787/connections -H "$H" -H 'Content-Type: application/json' -d '{
  "name": "stock sync",
  "steps": [
    { "type": "when", "left": "{{input.sku}}", "op": "not_equals", "right": "{{state.last.sku}}" },
    { "type": "fetch", "url": "https://shop.example.com/api/stock", "method": "POST", "body": { "sku": "{{input.sku}}" } },
    { "type": "transform", "output": { "sku": "{{input.sku}}", "synced_at": "{{meta.now}}" } }
  ]
}'

# push data in, read the latest result out — each site uses ITS OWN key here
SITE=bscs_...
curl -X POST "localhost:8787/c/<slug>/in" -H "Authorization: Bearer $SITE" \
  -H 'Content-Type: application/json' -d '{"sku":"A-1"}'
curl "localhost:8787/c/<slug>/out" -H "Authorization: Bearer $SITE"

Give each site the key that was issued for it. Never hand a site the admin key: it is the only credential that can register sites, define connections and mint keys.

API

Method Path Key Description
GET / Public health check ({ service, version, initialised }).
GET/POST/DELETE /sites · /sites/:slug admin Manage connected sites. POST returns the new site's key, once.
POST/DELETE /sites/:slug/key admin Rotate / revoke one site's key. Rotating kills the old one immediately.
GET/POST /connections · /connections/:slug admin Define / inspect connections.
POST /c/:slug/in admin or site Run the connection over the posted JSON.
GET /c/:slug/out admin or site Latest successful result.
GET /c/:slug/runs admin Recent run history, with pushed_by naming the site.

A site key used on an admin endpoint gets 403, not 401 — it is a valid key being used beyond what it is for.

Steps

  • fetch{ "type":"fetch", "url", "method"?, "headers"?, "body"? }{ status, body }.
  • transform{ "type":"transform", "output": <any JSON with {{placeholders}}> }.
  • when{ "type":"when", "left", "op"?, "right" } (op: equals | not_equals | contains, default not_equals). If false the run stops silently — nothing is stored.

Placeholders

{{input.*}} what you pushed · {{prev.*}} previous step output · {{steps.N.*}} step by index · {{state.last.*}} previous successful result · {{meta.now}} timestamp.

CLI

bruncsoft-connect init                  mint the ADMIN key (once)
bruncsoft-connect start [--port N] [--host H] [--restrict-private]
bruncsoft-connect key:rotate            new admin key, retire the old one
bruncsoft-connect sites                 list sites and their key labels
bruncsoft-connect site:add --name "My Shop" [--url https://shop.example.com]
                                        register a site and issue ITS key
bruncsoft-connect site:key --site my-shop
                                        rotate one site's key

Options: --data DIR (default ./data), --port (8787), --host (127.0.0.1), --restrict-private (block fetch to private/loopback addresses — off by default, since a self-hosted hub usually wants to reach your internal sites).

Security

  • Every key is 512-bit CSPRNG, stored only as a SHA-256 hash, and carries a checksum that rejects typos offline. The admin key is compared in constant time; a site key is resolved by hash lookup, which reveals nothing to anyone who cannot produce the hash.
  • One key per site. Rotate a site with site:key --site <slug> or POST /sites/:slug/key; revoke it with DELETE /sites/:slug/key. Deleting a site deletes its key. Rotating the admin key leaves site keys alone, and vice versa.
  • A site key cannot manage anything, so it cannot escalate: no new sites, no new connections, no new keys, and no reading another site's run history.
  • data/connect.db is created 0600 (owner-only) and holds every key hash.
  • Bind to 127.0.0.1 and put it behind your own HTTPS reverse proxy; if you bind to a public interface, firewall it. Request bodies are capped at 256 KB; fetch responses at 512 KB with a 10 s timeout and redirect: error.
  • Run history never stores request headers or tokens.

Test

npm test

About

Bruncsoft Connect — self-hosted integration hub. Connect your sites through one local API, secured by a 512-bit key only you hold. Nothing runs on anyone elses server.

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages