diff --git a/common/components/EventManager.php b/common/components/EventManager.php index 721a64f64..eadac283a 100644 --- a/common/components/EventManager.php +++ b/common/components/EventManager.php @@ -5,10 +5,14 @@ use Segment\Segment; use Yii; use yii\base\Component; +use yii\base\InvalidConfigException; use Aws\Sqs\SqsClient; use Aws\Exception\AwsException; use yii\httpclient\Client; +/** + * Coordinates analytics, queue, endpoint, and webhook event delivery. + */ class EventManager extends Component { /** @@ -51,6 +55,11 @@ class EventManager extends Component */ public $sqsEndpoint; + /** + * @var string|null bearer token for the event microservice endpoint + */ + public $sqsEndpointApiKey; + /** * @var string Mixpanel key */ @@ -395,9 +404,19 @@ public function track($event, $eventData, $timestamp = null, $userId = null, $on } /** - * API call for webhook + * Send a JSON request to the configured SQS endpoint with a required bearer token. + * + * @param string $method HTTP method to use + * @param string $url endpoint URL to call + * @param array $data JSON payload to send + * @return \yii\httpclient\Response + * @throws InvalidConfigException when EVENT_MANAGER_ENDPOINT_API_KEY is not configured */ public function call($method, $url, $data = []) { + if (trim((string) $this->sqsEndpointApiKey) === '') { + throw new InvalidConfigException('EVENT_MANAGER_ENDPOINT_API_KEY must be configured before sending SQS endpoint events.'); + } + $client = new Client(); return $client->createRequest() @@ -406,7 +425,7 @@ public function call($method, $url, $data = []) { ->setFormat(Client::FORMAT_JSON) ->setData($data) ->addHeaders([ - 'Authorization' =>'Bearer QstN8_18LmILpl37r2zvdDCp5JjWPCNh', + 'Authorization' => 'Bearer ' . trim((string) $this->sqsEndpointApiKey), "Content-Type" => "application/json", 'User-Agent' => 'request', ]) @@ -421,4 +440,4 @@ public function flush() if($this->segmentKey) Segment::flush(); } -} \ No newline at end of file +} diff --git a/common/components/Yeaster.php b/common/components/Yeaster.php index 2f4465dbb..696d72571 100644 --- a/common/components/Yeaster.php +++ b/common/components/Yeaster.php @@ -2,6 +2,7 @@ namespace common\components; +use yii\base\InvalidConfigException; use yii\httpclient\Client; /** @@ -12,11 +13,41 @@ */ class Yeaster extends \yii\base\Component { - public $microserviceApiKey = "QstN8_18LmILpl37r2zvdDCp5JjWPCNh"; + /** + * @var string|null bearer token used to authenticate calls to the voicemail microservice + */ + public $microserviceApiKey; - //point to microservice handling voicemails, overriding from main-local.php + /** + * @var string base URL for the voicemail microservice, overridden from main-local.php + */ public $apiEndpoint = "http://localhost:3001"; + /** + * Build authenticated request headers and fail fast if the service token is missing. + * + * @return array + * @throws InvalidConfigException when YEASTER_MICROSERVICE_API_KEY is not configured + */ + private function authorizationHeaders() + { + if (trim((string) $this->microserviceApiKey) === '') { + throw new InvalidConfigException('YEASTER_MICROSERVICE_API_KEY must be configured before calling the voicemail microservice.'); + } + + return [ + 'Authorization' => 'Bearer ' . trim((string) $this->microserviceApiKey), + 'content-type' => 'application/json', + ]; + } + + /** + * Fetch a paginated voicemail listing from the Yeaster microservice. + * + * @param int $page page number to request + * @param int $limit maximum number of voicemails to return + * @return mixed decoded response payload + */ public function listVoicemails($page, $limit = 10) { $client = new Client(); @@ -24,15 +55,18 @@ public function listVoicemails($page, $limit = 10) { ->setMethod('GET') ->setUrl($this->apiEndpoint . '/list?page=' . $page . '&limit=' . $limit) ->setFormat(Client::FORMAT_JSON) - ->addHeaders([ - 'Authorization' => 'Bearer ' . $this->microserviceApiKey, - 'content-type' => 'application/json', - ]) + ->addHeaders($this->authorizationHeaders()) ->send(); return $response->getData(); } + /** + * Fetch a single voicemail payload from the Yeaster microservice. + * + * @param int|string $id voicemail identifier + * @return string raw response content + */ public function viewVoicemail($id) { $client = new Client(); @@ -40,15 +74,18 @@ public function viewVoicemail($id) { ->setMethod('GET') ->setUrl($this->apiEndpoint . '/view/'. $id) ->setFormat(Client::FORMAT_JSON) - ->addHeaders([ - 'Authorization' => 'Bearer ' . $this->microserviceApiKey, - 'content-type' => 'application/json', - ]) + ->addHeaders($this->authorizationHeaders()) ->send(); return $response->content; } + /** + * Download a voicemail recording from the Yeaster microservice. + * + * @param int|string $id voicemail identifier + * @return string raw response content + */ public function downloadVoicemail($id) { $client = new Client(); @@ -56,12 +93,9 @@ public function downloadVoicemail($id) { ->setMethod('GET') ->setUrl($this->apiEndpoint . '/download/'. $id) ->setFormat(Client::FORMAT_JSON) - ->addHeaders([ - 'Authorization' => 'Bearer ' . $this->microserviceApiKey, - 'content-type' => 'application/json', - ]) + ->addHeaders($this->authorizationHeaders()) ->send(); return $response->content; } -} \ No newline at end of file +} diff --git a/docs/setup.md b/docs/setup.md index 53550fa5f..3c3e6bf5a 100644 --- a/docs/setup.md +++ b/docs/setup.md @@ -31,6 +31,34 @@ Use the provided script in the project root: ./run-tests.sh ``` +### Service Integration Secrets + +Keep service API tokens in deployment environment variables instead of checked-in +config files or browser bundles: + +```bash +WALLET_API_KEY= +YEASTER_MICROSERVICE_API_KEY= +EVENT_MANAGER_ENDPOINT_API_KEY= +``` + +`WALLET_API_KEY` is used by the legacy wallet integration when enabled. +`YEASTER_MICROSERVICE_API_KEY` authenticates voicemail microservice requests. +`EVENT_MANAGER_ENDPOINT_API_KEY` authenticates EventManager calls to the SQS +bridge endpoint when `sqsEndpoint` is configured. + +Configure these values in each deployment environment that enables the +corresponding integration. Production and shared staging environments should use +provider-issued tokens from the wallet service, voicemail microservice, and SQS +bridge service owners; local development can leave an integration unset only +when that feature is not exercised. + +Missing values are treated as disabled or invalid credentials. Wallet requests +must not be sent without `WALLET_API_KEY`. Voicemail calls fail fast before +emitting an empty `Authorization` header when `YEASTER_MICROSERVICE_API_KEY` is +missing. EventManager calls to the SQS bridge fail fast when +`EVENT_MANAGER_ENDPOINT_API_KEY` is missing and `sqsEndpoint` is configured. + ## Server Requirements ### PHP Extensions @@ -56,4 +84,4 @@ cd console && ../yii algolia/index candidate ```bash ./yii cron/update-candidate-stats ./yii cron/update-company-stats -``` \ No newline at end of file +``` diff --git a/environments/circle-ci/common/config/main-local.php b/environments/circle-ci/common/config/main-local.php index 3950e0d03..9d8e53ecf 100644 --- a/environments/circle-ci/common/config/main-local.php +++ b/environments/circle-ci/common/config/main-local.php @@ -17,12 +17,13 @@ ], 'walletManager' => [ 'class' => 'common\components\WalletManager', - 'apiKey' => 'QSw2ByGUITXFNjJVNNjyzxdbvYP9rXbG', + 'apiKey' => getenv('WALLET_API_KEY') ?: null, 'apiEndpoint' => 'https://webhook.dev.wallet.bawes.net/v1', 'companyWalletUserID' => 'user_fcac8a5f-52a2-11ed-a68e-d85ed3a264df' ], 'yeaster' => [ 'class' => 'common\components\Yeaster', + 'microserviceApiKey' => getenv('YEASTER_MICROSERVICE_API_KEY') ?: null, "apiEndpoint" => "http://localhost:3001" ], 'mailer' => [ @@ -53,6 +54,7 @@ ], 'eventManager' => [ 'class' => 'common\components\EventManager', + 'sqsEndpointApiKey' => getenv('EVENT_MANAGER_ENDPOINT_API_KEY') ?: null, "sqsRagion" => "eu-west-2", "sqsKey" => "AKIAWMITDJRKXNWDOBNJ", "sqsSecret" => "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", diff --git a/environments/dev-server-nginx-debug/common/config/main-local.php b/environments/dev-server-nginx-debug/common/config/main-local.php index 16ca69de9..7b6936b46 100644 --- a/environments/dev-server-nginx-debug/common/config/main-local.php +++ b/environments/dev-server-nginx-debug/common/config/main-local.php @@ -17,12 +17,13 @@ ], 'walletManager' => [ 'class' => 'common\components\WalletManager', - 'apiKey' => 'QSw2ByGUITXFNjJVNNjyzxdbvYP9rXbG', + 'apiKey' => getenv('WALLET_API_KEY') ?: null, 'apiEndpoint' => 'https://webhook.dev.wallet.bawes.net/v1', 'companyWalletUserID' => 'user_fcac8a5f-52a2-11ed-a68e-d85ed3a264df' ], 'yeaster' => [ 'class' => 'common\components\Yeaster', + 'microserviceApiKey' => getenv('YEASTER_MICROSERVICE_API_KEY') ?: null, "apiEndpoint" => "http://localhost:3001" ], 'xero' => [ @@ -84,6 +85,7 @@ ],*/ 'eventManager' => [ 'class' => 'common\components\EventManager', + 'sqsEndpointApiKey' => getenv('EVENT_MANAGER_ENDPOINT_API_KEY') ?: null, "sqsRagion" => "eu-west-2", "sqsKey" => "AKIAWMITDJRKXNWDOBNJ", "sqsSecret" => "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", diff --git a/environments/dev-server-nginx/common/config/main-local.php b/environments/dev-server-nginx/common/config/main-local.php index e0a79505f..e0c77ba35 100644 --- a/environments/dev-server-nginx/common/config/main-local.php +++ b/environments/dev-server-nginx/common/config/main-local.php @@ -17,12 +17,13 @@ ], 'walletManager' => [ 'class' => 'common\components\WalletManager', - 'apiKey' => 'QSw2ByGUITXFNjJVNNjyzxdbvYP9rXbG', + 'apiKey' => getenv('WALLET_API_KEY') ?: null, 'apiEndpoint' => 'https://webhook.dev.wallet.bawes.net/v1', 'companyWalletUserID' => 'user_fcac8a5f-52a2-11ed-a68e-d85ed3a264df' ], 'yeaster' => [ 'class' => 'common\components\Yeaster', + 'microserviceApiKey' => getenv('YEASTER_MICROSERVICE_API_KEY') ?: null, "apiEndpoint" => "http://localhost:3001" ], 'xero' => [ @@ -82,6 +83,7 @@ ],*/ 'eventManager' => [ 'class' => 'common\components\EventManager', + 'sqsEndpointApiKey' => getenv('EVENT_MANAGER_ENDPOINT_API_KEY') ?: null, "sqsRagion" => "eu-west-2", "sqsKey" => "AKIAWMITDJRKXNWDOBNJ", "sqsSecret" => "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", diff --git a/environments/dev-server-railway/common/config/main-local.php b/environments/dev-server-railway/common/config/main-local.php index e9d8bc3ce..fbce2af41 100644 --- a/environments/dev-server-railway/common/config/main-local.php +++ b/environments/dev-server-railway/common/config/main-local.php @@ -18,13 +18,14 @@ //todo: replace with wallet from sandbox 'walletManager' => [ 'class' => 'common\components\WalletManager', - 'apiKey' => 'QSw2ByGUITXFNjJVNNjyzxdbvYP9rXbG', + 'apiKey' => getenv('WALLET_API_KEY') ?: null, 'apiEndpoint' => 'https://webhook.dev.wallet.bawes.net/v1', 'companyWalletUserID' => 'user_fcac8a5f-52a2-11ed-a68e-d85ed3a264df' ], //todo: replace with yeaster from sandbox 'yeaster' => [ 'class' => 'common\components\Yeaster', + 'microserviceApiKey' => getenv('YEASTER_MICROSERVICE_API_KEY') ?: null, "apiEndpoint" => "http://localhost:3001" ], 'xero' => [ @@ -86,6 +87,7 @@ ],*/ 'eventManager' => [ 'class' => 'common\components\EventManager', + 'sqsEndpointApiKey' => getenv('EVENT_MANAGER_ENDPOINT_API_KEY') ?: null, "sqsRagion" => "eu-west-2", "sqsKey" => "AKIAWMITDJRKXNWDOBNJ", "sqsSecret" => "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", diff --git a/environments/dev-server/common/config/main-local.php b/environments/dev-server/common/config/main-local.php index ee588a95f..2efdd412e 100644 --- a/environments/dev-server/common/config/main-local.php +++ b/environments/dev-server/common/config/main-local.php @@ -17,12 +17,13 @@ ], 'walletManager' => [ 'class' => 'common\components\WalletManager', - 'apiKey' => 'QSw2ByGUITXFNjJVNNjyzxdbvYP9rXbG', + 'apiKey' => getenv('WALLET_API_KEY') ?: null, 'apiEndpoint' => 'https://webhook.dev.wallet.bawes.net/v1', 'companyWalletUserID' => 'user_fcac8a5f-52a2-11ed-a68e-d85ed3a264df' ], 'yeaster' => [ 'class' => 'common\components\Yeaster', + 'microserviceApiKey' => getenv('YEASTER_MICROSERVICE_API_KEY') ?: null, "apiEndpoint" => "http://localhost:3001" ], 'xero' => [ @@ -87,6 +88,7 @@ ],*/ 'eventManager' => [ 'class' => 'common\components\EventManager', + 'sqsEndpointApiKey' => getenv('EVENT_MANAGER_ENDPOINT_API_KEY') ?: null, "sqsRagion" => "eu-west-2", "sqsKey" => "AKIAWMITDJRKXNWDOBNJ", "sqsSecret" => "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", diff --git a/environments/dev/common/config/main-local.php b/environments/dev/common/config/main-local.php index 75e6afd0b..c8a8fc7eb 100644 --- a/environments/dev/common/config/main-local.php +++ b/environments/dev/common/config/main-local.php @@ -17,12 +17,13 @@ ], 'walletManager' => [ 'class' => 'common\components\WalletManager', - 'apiKey' => 'QSw2ByGUITXFNjJVNNjyzxdbvYP9rXbG', + 'apiKey' => getenv('WALLET_API_KEY') ?: null, 'apiEndpoint' => 'http://localhost/wallet/webhook/web/v1',//todo: 'companyWalletUserID' => 'user_fcac8a5f-52a2-11ed-a68e-d85ed3a264df' ], 'yeaster' => [ 'class' => 'common\components\Yeaster', + 'microserviceApiKey' => getenv('YEASTER_MICROSERVICE_API_KEY') ?: null, "apiEndpoint" => "http://localhost:3001" ], 'cache' => [ @@ -66,6 +67,7 @@ ], 'eventManager' => [ 'class' => 'common\components\EventManager', + 'sqsEndpointApiKey' => getenv('EVENT_MANAGER_ENDPOINT_API_KEY') ?: null, "sqsRagion" => "eu-west-2", "sqsKey" => "AKIAWMITDJRKXNWDOBNJ", "sqsSecret" => "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", diff --git a/environments/docker/common/config/main-local.php b/environments/docker/common/config/main-local.php index 2e5d08211..b37c889a3 100644 --- a/environments/docker/common/config/main-local.php +++ b/environments/docker/common/config/main-local.php @@ -27,6 +27,7 @@ ], 'yeaster' => [ 'class' => 'common\components\Yeaster', + 'microserviceApiKey' => getenv('YEASTER_MICROSERVICE_API_KEY') ?: null, "apiEndpoint" => "http://192.168.1.5:3001" ], 'xero' => [ @@ -41,7 +42,7 @@ ], 'walletManager' => [ 'class' => 'common\components\WalletManager', - 'apiKey' => 'QSw2ByGUITXFNjJVNNjyzxdbvYP9rXbG', + 'apiKey' => getenv('WALLET_API_KEY') ?: null, 'apiEndpoint' => 'http://192.168.1.5/wallet/webhook/web/v1', 'companyWalletUserID' => 'user_fcac8a5f-52a2-11ed-a68e-d85ed3a264df' ], @@ -73,6 +74,7 @@ ], 'eventManager' => [ 'class' => 'common\components\EventManager', + 'sqsEndpointApiKey' => getenv('EVENT_MANAGER_ENDPOINT_API_KEY') ?: null, "sqsRagion" => "eu-west-2", "sqsKey" => "AKIAWMITDJRKXNWDOBNJ", "sqsSecret" => "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", diff --git a/environments/krushn-nginx/common/config/main-local.php b/environments/krushn-nginx/common/config/main-local.php index 8573aa6bb..36cd91612 100644 --- a/environments/krushn-nginx/common/config/main-local.php +++ b/environments/krushn-nginx/common/config/main-local.php @@ -10,6 +10,7 @@ ], 'yeaster' => [ 'class' => 'common\components\Yeaster', + 'microserviceApiKey' => getenv('YEASTER_MICROSERVICE_API_KEY') ?: null, "apiEndpoint" => "http://localhost:3001" ], 'walletDb' => [ @@ -41,7 +42,7 @@ ], 'walletManager' => [ 'class' => 'common\components\WalletManager', - 'apiKey' => 'QSw2ByGUITXFNjJVNNjyzxdbvYP9rXbG', + 'apiKey' => getenv('WALLET_API_KEY') ?: null, 'apiEndpoint' => 'http://localhost/wallet/webhook/web/v1', 'companyWalletUserID' => 'user_fcac8a5f-52a2-11ed-a68e-d85ed3a264df' ], @@ -74,6 +75,7 @@ ], 'eventManager' => [ 'class' => 'common\components\EventManager', + 'sqsEndpointApiKey' => getenv('EVENT_MANAGER_ENDPOINT_API_KEY') ?: null, // "sqsRagion" => "eu-west-2", // "sqsKey" => "AKIAWMITDJRKXNWDOBNJ", // "sqsSecret" => "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", diff --git a/environments/krushn/common/config/main-local.php b/environments/krushn/common/config/main-local.php index 6a2fb61a1..f134c41ae 100644 --- a/environments/krushn/common/config/main-local.php +++ b/environments/krushn/common/config/main-local.php @@ -10,6 +10,7 @@ ], 'yeaster' => [ 'class' => 'common\components\Yeaster', + 'microserviceApiKey' => getenv('YEASTER_MICROSERVICE_API_KEY') ?: null, "apiEndpoint" => "http://localhost:3001" ], 'walletDb' => [ @@ -41,7 +42,7 @@ ], 'walletManager' => [ 'class' => 'common\components\WalletManager', - 'apiKey' => 'QSw2ByGUITXFNjJVNNjyzxdbvYP9rXbG', + 'apiKey' => getenv('WALLET_API_KEY') ?: null, 'apiEndpoint' => 'http://localhost/wallet/webhook/web/v1', 'companyWalletUserID' => 'user_fcac8a5f-52a2-11ed-a68e-d85ed3a264df' ], @@ -73,6 +74,7 @@ ], 'eventManager' => [ 'class' => 'common\components\EventManager', + 'sqsEndpointApiKey' => getenv('EVENT_MANAGER_ENDPOINT_API_KEY') ?: null, // "sqsRagion" => "eu-west-2", // "sqsKey" => "AKIAWMITDJRKXNWDOBNJ", // "sqsSecret" => "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", diff --git a/environments/prod-nginx/common/config/main-local.php b/environments/prod-nginx/common/config/main-local.php index b5c8b2841..c5caf1578 100644 --- a/environments/prod-nginx/common/config/main-local.php +++ b/environments/prod-nginx/common/config/main-local.php @@ -52,7 +52,7 @@ ], 'walletManager' => [ 'class' => 'common\components\WalletManager', - 'apiKey' => 'POAO-BiBxj-Oqp2XOIDZgSDrTYJxOa3M', + 'apiKey' => getenv('WALLET_API_KEY') ?: null, ], 'redis' => [ 'class' => 'yii\redis\Connection', @@ -142,6 +142,7 @@ ],*/ 'eventManager' => [ 'class' => 'common\components\EventManager', + 'sqsEndpointApiKey' => getenv('EVENT_MANAGER_ENDPOINT_API_KEY') ?: null, //todo: commenting down as it's slowing down all apis //"sqsRagion" => "eu-west-2", //"sqsKey" => "AKIAWMITDJRKXNWDOBNJ", @@ -179,6 +180,7 @@ ], 'yeaster' => [ 'class' => 'common\components\Yeaster', + 'microserviceApiKey' => getenv('YEASTER_MICROSERVICE_API_KEY') ?: null, "apiEndpoint" => "http://ec2-18-130-75-235.eu-west-2.compute.amazonaws.com:3001" ], 'urlManagerStaff' => [ diff --git a/environments/prod-railway/common/config/main-local.php b/environments/prod-railway/common/config/main-local.php index f8b14d079..b1b363ba9 100644 --- a/environments/prod-railway/common/config/main-local.php +++ b/environments/prod-railway/common/config/main-local.php @@ -30,7 +30,7 @@ ], 'walletManager' => [ 'class' => 'common\components\WalletManager', - 'apiKey' => 'POAO-BiBxj-Oqp2XOIDZgSDrTYJxOa3M', + 'apiKey' => getenv('WALLET_API_KEY') ?: null, ], 'redis' => [ 'class' => 'yii\redis\Connection', @@ -126,6 +126,7 @@ ],*/ 'eventManager' => [ 'class' => 'common\components\EventManager', + 'sqsEndpointApiKey' => getenv('EVENT_MANAGER_ENDPOINT_API_KEY') ?: null, //todo: commenting down as it's slowing down all apis //"sqsRagion" => "eu-west-2", //"sqsKey" => "AKIAWMITDJRKXNWDOBNJ", @@ -167,6 +168,7 @@ ], 'yeaster' => [ 'class' => 'common\components\Yeaster', + 'microserviceApiKey' => getenv('YEASTER_MICROSERVICE_API_KEY') ?: null, "apiEndpoint" => "http://ec2-18-130-75-235.eu-west-2.compute.amazonaws.com:3001" ], 'urlManagerStaff' => [ diff --git a/environments/prod/common/config/main-local.php b/environments/prod/common/config/main-local.php index d8f901035..7c9103f99 100644 --- a/environments/prod/common/config/main-local.php +++ b/environments/prod/common/config/main-local.php @@ -52,7 +52,7 @@ ], 'walletManager' => [ 'class' => 'common\components\WalletManager', - 'apiKey' => 'imx4kpyVCXbi7sVy-zEvEITL63sQWisn',//QSw2ByGUITXFNjJVNNjyzxdbvYP9rXbG + 'apiKey' => getenv('WALLET_API_KEY') ?: null ], 'redis' => [ 'class' => 'yii\redis\Connection', @@ -128,6 +128,7 @@ ],*/ 'eventManager' => [ 'class' => 'common\components\EventManager', + 'sqsEndpointApiKey' => getenv('EVENT_MANAGER_ENDPOINT_API_KEY') ?: null, //todo: commenting down as it's slowing down all apis //"sqsRagion" => "eu-west-2", //"sqsKey" => "AKIAWMITDJRKXNWDOBNJ", @@ -165,6 +166,7 @@ ], 'yeaster' => [ 'class' => 'common\components\Yeaster', + 'microserviceApiKey' => getenv('YEASTER_MICROSERVICE_API_KEY') ?: null, "apiEndpoint" => "http://ec2-18-130-75-235.eu-west-2.compute.amazonaws.com:3001" ], 'urlManagerStaff' => [ diff --git a/scripts/check-service-token-hardening.py b/scripts/check-service-token-hardening.py new file mode 100644 index 000000000..da6bdc28a --- /dev/null +++ b/scripts/check-service-token-hardening.py @@ -0,0 +1,77 @@ +from pathlib import Path +import re +import sys + +ROOT = Path(__file__).resolve().parents[1] + +SECRET_PATTERNS = [ + ("raw microservice bearer token", re.compile(r"Bearer\s+[A-Za-z0-9_-]{24,}")), + ("browser-bundled Xero bearer token", re.compile(r"Bearer\s+eyJhbGciOiJSUzI1NiIsImtpZCI6")), +] + +REQUIRED_ENV_REFERENCES = [ + ("WALLET_API_KEY", ROOT / "environments"), + ("YEASTER_MICROSERVICE_API_KEY", ROOT / "environments"), + ("EVENT_MANAGER_ENDPOINT_API_KEY", ROOT / "environments"), +] + +SEARCH_SUFFIXES = {".php", ".js", ".md", ".yml", ".yaml", ".json"} +SKIP_DIRS = {".git", "vendor"} + + +def iter_files(): + """Yield repository files that can contain checked-in service tokens.""" + for path in ROOT.rglob("*"): + if not path.is_file() or path.suffix not in SEARCH_SUFFIXES: + continue + if any(part in SKIP_DIRS for part in path.parts): + continue + yield path + + +def main(): + """Validate service tokens are referenced from runtime environment sources.""" + failures = [] + for path in iter_files(): + text = path.read_text(encoding="utf-8", errors="ignore") + rel = path.relative_to(ROOT) + for label, pattern in SECRET_PATTERNS: + if pattern.search(text): + failures.append(f"{rel}: contains {label}") + + wallet_literal = re.compile( + r"['\"]walletManager['\"]\s*=>\s*\[[\s\S]*?['\"]apiKey['\"]\s*=>\s*['\"](?!\s*\))", + re.MULTILINE, + ) + for path in (ROOT / "environments").rglob("main-local.php"): + text = path.read_text(encoding="utf-8", errors="ignore") + if wallet_literal.search(text): + failures.append(f"{path.relative_to(ROOT)}: walletManager apiKey is not env-backed") + + for env_name, base in REQUIRED_ENV_REFERENCES: + found = False + env_pattern = re.escape(env_name) + access_pattern = re.compile( + rf"(?:getenv|env)\s*\(\s*['\"]{env_pattern}['\"]\s*\)" + rf"|\$_(?:ENV|SERVER)\s*\[\s*['\"]{env_pattern}['\"]\s*\]" + ) + for path in base.rglob("*.php"): + text = path.read_text(encoding="utf-8", errors="ignore") + if access_pattern.search(text): + found = True + break + if not found: + failures.append(f"missing environment reference: {env_name}") + + if failures: + print("Service token hardening check failed:") + for failure in failures: + print(f"- {failure}") + return 1 + + print("Service token hardening check passed.") + return 0 + + +if __name__ == "__main__": + sys.exit(main()) diff --git a/staff/web/build/p-5e3b44c4.entry.js b/staff/web/build/p-5e3b44c4.entry.js index 5df2b1f29..58c4167ef 100644 --- a/staff/web/build/p-5e3b44c4.entry.js +++ b/staff/web/build/p-5e3b44c4.entry.js @@ -1 +1 @@ -import{r as o,h as t,H as e}from"./p-a94aef08.js";const r=class{constructor(t){o(this,t)}componentWillLoad(){const o=new Headers;return o.set("Content-Type","application/json"),o.set("Authorization","Bearer eyJhbGciOiJSUzI1NiIsImtpZCI6IjFDQUY4RTY2NzcyRDZEQzAyOEQ2NzI2RkQwMjYxNTgxNTcwRUZDMTkiLCJ0eXAiOiJKV1QiLCJ4NXQiOiJISy1PWm5jdGJjQW8xbkp2MENZVmdWY09fQmsifQ"),fetch("https://api.xero.com/api.xro/2.0/Reports/ProfitAndLoss",{headers:o}).then((o=>o.json())).then((o=>{console.log(o),this.profitData=o}))}render(){return t(e,null,"Xero test")}};r.style=":host{display:block}";export{r as xero_profit} \ No newline at end of file +import{r as o,h as t,H as e}from"./p-a94aef08.js";const r=class{constructor(t){o(this,t)}componentWillLoad(){this.profitData=null}render(){return t(e,null,"Xero test disabled")}};r.style=":host{display:block}";export{r as xero_profit}