Commit Graph
16 Commits
Author SHA1 Message Date
Claude 876fd6553b Add inbound concurrency cap, bump defaults to 10/10, make caps live-editable
Adds an inbound concurrent-call cap mirroring the existing outbound one -
outbound alone didn't protect against an inbound call-flood, which also
costs money per-minute on VoIP.ms. Both defaults bumped from 3 to 10.

Moves the cap numbers themselves out of static dialplan text and into a new
pstn-limits.conf, read live via AST_CONFIG() the same way permission tiers
already are - changing either cap takes effect on the next call, no
Asterisk restart, no reinstall. "update in place" never touches this file,
matching the existing protection for pstn-permissions.conf/.env/firewall/
Caddy config.

Adds a concurrency-caps card to security-dashboard.sh's "PSTN Trunk" tab,
above the existing permissions table, so both caps are visible and editable
from the same web page. Tested against a real running instance of the
Python app: default fallback when the file doesn't exist yet, save/persist,
invalid-input rejection, and a bash-to-Python round trip on the generated
file format.

Inbound dialplan ordering mirrors outbound's existing pattern: permission
check (is any ring-group member authorized for this caller) before the
concurrency check, consistent with outbound's tier-check-then-busy-check
order.
2026-07-22 00:49:41 +00:00
Claude 3bd952e55d PSTN trunk: 3-tier live permissions + Security Dashboard web UI + dual target
Reworks the outbound permission model from a flat allow-list into three
per-extension tiers (internal / restricted / full), addressing the ask for
extensions that can only reach pre-approved numbers plus extensions with
full US calling, while internal extension-to-extension dialing and ring
groups stay ungated for everyone regardless of tier.

Permissions now live in pstn-permissions.conf, read by the dialplan via
Asterisk's AST_CONFIG() on every call instead of being baked into static
dialplan text - editing that file takes effect on the next call, no
Asterisk restart and no re-running the installer. "update in place" mode
never touches this file (same protection this repo's update-mode
convention already gives .env/firewall/Caddy config); only a "fresh"
reinstall (with confirmation) or the web UI change it.

Adds a "PSTN Trunk" tab to services/security-dashboard.sh: lists every
extension (parsed from pjsip.conf) with its live tier and approved numbers,
editable with no restart - this is what makes the tier model actually
manageable day to day. Extracted the dashboard's systemd-unit writing into
its own function so "update" mode refreshes it too (previously only fresh
installs did), and generalized both the dashboard and the trunk service to
detect either asterisk-digital-ocean or the home/LAN asterisk install.

Inbound ring-group membership now checks each member's tier live per call
via an unrolled per-member dialplan block (full always rings, restricted
only if the caller's number is approved, internal never rings) rather than
a single static Dial() string.

Caught and fixed two real bugs during testing against a sandboxed vendor
copy and a live instance of the (stdlib-only) Python dashboard app:
- Asterisk Goto/GotoIf argument parsing: ring<ext>/skip<ext> are named
  priorities within the same extension (declared via "same => n(label),..."),
  not separate exten => entries, so jumping to them needs the single-argument
  Goto(label) form - the two-argument Goto(label,1) form used initially
  addresses a different, nonexistent extension named "label" instead.
- A security-relevant REGEX() direction issue: the inbound Caller-ID check
  initially interpolated attacker-influenced call data into the PATTERN side
  of a REGEX() match rather than the tested-string side, which would let a
  crafted Caller-ID forge a match against an unrelated approved-numbers
  entry. Fixed by keeping the admin-controlled approved-list as the pattern
  and the live call data as the string being tested, consistently on both
  the outbound and inbound checks.

Verified end-to-end: dialplan/pjsip generation and vendor-file patching
(idempotent, syntax-checked) as before, plus the new permission-file
round-trip between bash and Python, and the dashboard's new API endpoints
exercised against a real running Python server (extension parsing, tier
changes, number normalization, invalid-input rejection, atomic file writes).
2026-07-21 23:59:50 +00:00
Claude 1e2a3743ab Rework PSTN trunk: role-based permissions, ring-groups, ntfy spend alerts
Generalizes services/pstn-trunk.sh (renamed from voipms-trunk.sh in the
prior commit) away from VoIP.ms specifics - any IP-authenticated SIP
provider works, VoIP.ms is just the suggested default. Adds:

- Role-based outbound permission: a configurable allow-list of extensions
  that may dial PSTN numbers (regex-gated on CHANNEL(peername)), separate
  from internal extension-to-extension dialing which stays open to everyone
  regardless. Blank list preserves the original "everyone can dial out"
  behavior.
- Inbound ring-group: rings a configurable list of extensions instead of a
  single hardcoded one.
- ntfy alerts: immediate on denied (unauthorized extension) or rejected
  (concurrency cap hit) calls, plus an hourly cron-driven check that alerts
  once per month when estimated spend crosses a threshold and every hour
  call volume looks like a burst. Uses a self-contained pipe-delimited call
  log rather than Asterisk's CDR, to avoid depending on CDR module
  availability and CSV comma-quoting.
- Settings persisted to .pstn-trunk.env so "update in place" reapplies
  everything from that file instead of fragile re-parsing out of generated
  Asterisk config (which had a real bug: update mode was extracting the
  wrong Dial(PJSIP/...) line).

Tested end-to-end against a sandboxed copy of the real vendor files:
permission-gate regex, ring-group dial-string construction, ntfy line
injection/removal, and the usage-alert script's threshold/burst/monthly-
dedup logic all verified with synthetic data. Caught and fixed a sed `&`
escaping bug in the ring-group substitution before it shipped (RING_DIAL
contains literal `&` join characters, which sed's replacement syntax
otherwise treats as "insert the match").
2026-07-21 23:38:08 +00:00
Claude 2ac2982e38 Add voipms-trunk service: US-only outbound PSTN, max 3 concurrent calls
Adds a VoIP.ms SIP trunk on top of asterisk-digital-ocean: IP-authenticated
trunk (no password stored), NANP-only outbound dialplan, a global 3-call
concurrent cap via GROUP()/GROUP_COUNT(), and inbound routing to one
extension. Config lives in its own include files rather than being
appended directly to pjsip.conf/extensions.conf, since Easy Asterisk fully
regenerates both from its own internal state — the includes are patched
into the vendor's generator functions so they survive that regeneration.

Wires the new service into setup.sh's is_installed() and README's services
table, and updates docs/pstn-calling-voipms-plan.md to reflect what's now
implemented vs. still open (spend/volume alerting, live-account
verification).
2026-07-21 23:13:59 +00:00
Claude 719f9117be Record inbound decision and cost estimate in VoIP.ms planning doc
Inbound (DID) is now decided as wanted, not outbound-only. Adds a cost
estimate table for 100 min/month each direction, and clarifies that
NANP-only restriction bounds cost-per-minute but not burn speed, so the
concurrent-call cap and spend alert are required before funding a live
trunk, not optional hardening.
2026-07-21 22:41:22 +00:00
Claude ed5b2b8daa docs: add PSTN calling (VoIP.ms) planning notes
Captures the toll-fraud / prepaid-cap research and decisions from a design
discussion (provider: VoIP.ms, US-only calling for now) so implementation
can be picked up in a future session without re-deriving the background.
Nothing implemented yet.
2026-07-21 22:04:15 +00:00
Claude 92fd67ec34 feat: auto-install msitools in both SWBF2 setup scripts
Both scripts now detect and install msitools if missing, supporting
apt-get (Debian/Ubuntu), dnf (Fedora), and pacman (Arch). Falls back
to a clear error if the package manager is not recognised.

Remove msitools from manual prerequisites in the doc.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01D8ckUJQtj1pH8jtAddBDZs
2026-06-22 16:31:42 +00:00
Claude 7f926c03af feat: add GE-Proton auto-install to both SWBF2 setup scripts
Both scripts now download and install GE-Proton10-34 if not already present:
- setup-swbf2-linux.sh: installs to ~/.steam/root/compatibilitytools.d/
- setup-swbf2-wolf.sh: installs into the WolfSteam container via docker cp + tar

Both pause after install and prompt the user to set GE-Proton in Steam
(Compatibility → Force) before continuing, since that step requires the GUI.

Update docs to reflect GE-Proton is now handled automatically.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01D8ckUJQtj1pH8jtAddBDZs
2026-06-22 16:15:24 +00:00
Claude 1b29873f62 docs: rename wolf-setup to linux-setup, native Linux section first
- Rename SWBF2-2017-wolf-setup.md -> SWBF2-2017-linux-setup.md
- Move Native Linux Steam section before Wolf/Moonlight section
- Update TOC link order to match

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01D8ckUJQtj1pH8jtAddBDZs
2026-06-22 14:37:46 +00:00
Claude 11a7c6529c docs: rewrite SWBF2 setup guide as clean how-to with native Linux section
- Remove editorial content (EA server speculation, 2005 alternative, opinions)
- Add native Linux Steam section covering all six setup steps
- Add separate key paths tables for Wolf and native
- Add native Linux troubleshooting commands alongside Wolf equivalents
- Rename title to reflect both platforms
- Fresh install table rewritten as factual survival matrix

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01D8ckUJQtj1pH8jtAddBDZs
2026-06-22 14:21:22 +00:00
Claude 4324ad7ce2 docs: add SWBF2 2017 discovery writeup explaining why the fix works
Long-form document tracing the actual discovery process: the wrong turns,
the aha moments, and the reasoning behind each step. Covers:

- Why EA is involved in a Steam game at all (link2ea:// architecture)
- JunoConfigureRegistry failure and why DISABLEROLLBACK was a dead end
- msiextract bypass as the actual solution
- Why direct system.reg edits don't survive reboots (wineserver ownership)
- The launch wrapper approach for registry persistence
- RPC_S_SERVER_UNAVAILABLE and EALocalHostSvc
- Wolf-specific bwrap capabilities mismatch
- localconfig.vdf atomic rename problem and chmod 555 fix

Written for sharing — no identifying information, explains the "why"
for each fix so readers can adapt if EA changes their MSI structure.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01D8ckUJQtj1pH8jtAddBDZs
2026-06-22 13:26:11 +00:00
Claude b756e7eedb docs: rewrite SWBF2-2017 guide with working msiextract + wrapper solution
Complete rewrite reflecting the actual working setup:
- msiextract on host bypasses JunoConfigureRegistry Wine incompatibility
- Wrapper script imports registry fixes via regedit through Steam's launch chain
- chmod 555 on config dir prevents Steam overwriting localconfig.vdf
- Honest fresh-install assessment table (what's automated vs one-time manual)
- Troubleshooting section covering all errors encountered
- Key paths reference table

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01D8ckUJQtj1pH8jtAddBDZs
2026-06-22 12:35:14 +00:00
Claude 5cff764d3b docs: add EA auth dependency context, login process, and longevity notes
Documents the EA account requirement, first-time login flow, credential
caching for machine transfers, community server options if EA shuts down,
and the SWBF2 2005 alternative for a launcher-free experience.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01D8ckUJQtj1pH8jtAddBDZs
2026-06-22 05:02:19 +00:00
Claude 6b385e62ba docs: update SWBF2 guide with direct-exe bypass and Origin registry spoof
Revised approach: skip link2ea:// and EA App account requirement entirely.
Launch starwarsbattlefrontii.exe directly via the wrapper, spoof Origin
registry entries so the game's built-in launcher check passes. Documents
what doesn't work and why (msiexec/bwrap/EA account issues).

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01D8ckUJQtj1pH8jtAddBDZs
2026-06-22 04:25:26 +00:00
Claude 0202515163 docs: add SWBF2 2017 Wolf/Moonlight setup guide
Documents the EA App installation workaround for Star Wars Battlefront II
(2017) running under Wolf/WolfSteam with GE-Proton10-34. Covers the bwrap
capability problem, Steam launch wrapper trick, msiextract bypass for the
JunoConfigureRegistry Wine incompatibility, and correct EA Desktop file layout.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01D8ckUJQtj1pH8jtAddBDZs
2026-06-22 03:56:56 +00:00
Claude a80eef0984 services: replace FileBrowser with FileBrowser Quantum
- Swaps image from filebrowser/filebrowser to gtstef/filebrowser:stable
- Uses ./data:/home/filebrowser/data volume layout (Quantum convention)
- Generates data/config.yaml instead of settings.json + database.db
- Mounts primary path as /files with defaultEnabled: true
- Deploys fbq-add-source.sh for adding extra directories post-install
- Updates README with Quantum-specific instructions

docs: save standalone bootstrap as docs/standalone-template.sh

Preserves the full standalone pattern from filebrowser.sh as the
reference template for adding standalone support to other services.

https://claude.ai/code/session_014CCYqVwW6d6f5dw1qRokYt
2026-06-08 15:37:52 +00:00