$assoc) { $groups = $assoc['groups'] ?? []; foreach (['corpus_builder', 'sase_participant', 'civic_professional'] as $group_key) { $gid = intval($groups[$group_key] ?? 0); if ($gid) { $r = q("SELECT xchan FROM pggrp_member WHERE gid = %d AND xchan = '%s' LIMIT 1", intval($gid), dbesc($observer) ); if ($r) return 'participant'; } } } return 'public'; } // ----------------------------------------------------------------------------- // CONTENT ROUTER // ----------------------------------------------------------------------------- function g1wallet_content() { if (function_exists('head_add_css')) { head_add_css('/addon/g1wallet/view/css/g1wallet.css'); } if (function_exists('head_add_js')) { // bip39 must load before g1wallet.js (g1wallet.js calls window.bip39). head_add_js('/addon/g1wallet/vendor/bip39-3.1.0.min.js'); head_add_js('/addon/g1wallet/view/js/g1wallet.js'); // Note: vendor/scrypt-js-3.0.1.min.js is NOT loaded. // scrypt is the obsolete Cesium1 / Duniter v1 derivation algorithm. // Duniter v2 / Ğecko uses entropy-as-seed (no KDF). The file is // retained in vendor/ for reference but is not wired anywhere. } $access = g1wallet_access_state(); $sub_route = strtolower(argv(1) ?? ''); if ($access === 'public') { return g1wallet_render_access_wall(); } switch ($sub_route) { case 'balance': // GET: return cached balance for the current session pubkey. // Placeholder — orchestrator query not yet implemented. return g1wallet_render_error('Balance fetch not yet implemented.'); case 'broadcast': // POST: relay signed Duniter transaction to orchestrator. if ($_SERVER['REQUEST_METHOD'] !== 'POST') { return g1wallet_render_error('POST required.'); } if (!g1wallet_verify_csrf()) { return g1wallet_render_error('Invalid form token. Please reload and try again.'); } return g1wallet_handle_broadcast_post(); case 'pubkey': // POST: store public key in channel settings after unlock. if ($_SERVER['REQUEST_METHOD'] !== 'POST') { return g1wallet_render_error('POST required.'); } if (!g1wallet_verify_csrf()) { return g1wallet_render_error('Invalid form token. Please reload and try again.'); } return g1wallet_handle_pubkey_post($access); default: // Wallet landing: unlock form or unlocked interface. return g1wallet_render_landing($access); } } // ----------------------------------------------------------------------------- // CSRF // ----------------------------------------------------------------------------- function g1wallet_csrf_token() { // Generates and stores a CSRF token for the current session. if (empty($_SESSION['g1wallet_csrf'])) { $_SESSION['g1wallet_csrf'] = bin2hex(random_bytes(16)); } return ''; } function g1wallet_verify_csrf() { // Returns true if the CSRF token in POST matches the session token. return isset($_POST['g1wallet_csrf'], $_SESSION['g1wallet_csrf']) && hash_equals($_SESSION['g1wallet_csrf'], $_POST['g1wallet_csrf']); }