diff --git a/common/config/main.php b/common/config/main.php index 793bdb35..c4a96a16 100644 --- a/common/config/main.php +++ b/common/config/main.php @@ -28,7 +28,7 @@ ], 'reCaptcha' => [ 'class' => 'common\components\ReCaptcha', - 'secretKey' => "6Lei9R4pAAAAAD5-OIUbCZeMQ00saNLKNuU62b4v" + 'secretKey' => getenv('RECAPTCHA_SECRET_KEY') ?: '', ], 'jwt' => [ 'class' => 'common\components\JWT' @@ -38,20 +38,18 @@ ], 'jira' => [ 'class' => 'common\components\JiraComponent', - 'jiraUrl' => 'https://bawes-studenthub.atlassian.net', - 'email' => 'kk@bawes.net', - 'apiToken' => 'eYVHMtAi16zN56M2PS3gB8AB' + 'jiraUrl' => getenv('JIRA_URL') ?: '', + 'email' => getenv('JIRA_EMAIL') ?: '', + 'apiToken' => getenv('JIRA_API_TOKEN') ?: '', ], 'algolia' => [ 'class' => 'common\components\Algolia', - 'appId' => 'VQF0F2SG4Y', - 'apiKey' => 'bce91c65c212d2bb20c079eb15c2283b', - // 'publicKey' => '381f91f1c08f4d2788a6821cad1ccbbb' + 'appId' => getenv('ALGOLIA_APP_ID') ?: '', + 'apiKey' => getenv('ALGOLIA_API_KEY') ?: '', ], 'ipstack' => [ 'class' => 'common\components\Ipstack', - //'accessKey' => 'fac3c2117d877e078e3e8fa7839d8204' - 'accessKey' => '911bdd76f42e7f' + 'accessKey' => getenv('IPINFO_ACCESS_TOKEN') ?: '', ], 'cloudinaryManager' => [ 'class' => 'common\components\CloudinaryManager', @@ -70,7 +68,7 @@ ], 'slack' => [ 'class' => 'understeam\slack\Client', - 'url' => 'https://hooks.slack.com/services/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', + 'url' => getenv('SLACK_WEBHOOK_URL') ?: '', 'username' => 'StudentHub', ], 'auth0' => [ diff --git a/common/config/params.php b/common/config/params.php index c5735aa3..b9e788ba 100644 --- a/common/config/params.php +++ b/common/config/params.php @@ -13,7 +13,7 @@ 'salaryDay' => 5, //salary should get transfer by 5th day of every month 'payment_notice_period' => '-35 days', 'candidate_photo' => 'https://res.cloudinary.com/studenthub/image/upload/v1596525812/', - 'google_api_key' => 'AIzaSyBSM8o4WSIIRn-sNhn-PvO2s0ovZuLDAaw', + 'google_api_key' => getenv('GOOGLE_MAPS_BROWSER_API_KEY') ?: '', 'mailThreshold' => 500, "aws_temp_access_key_id" => getenv('AWS_TEMP_BUCKET_KEY') ?: '', "aws_temp_secret_access_key" => getenv('AWS_TEMP_BUCKET_SECRET') ?: '', diff --git a/docs/setup.md b/docs/setup.md index 53550fa5..bf93f9e1 100644 --- a/docs/setup.md +++ b/docs/setup.md @@ -36,6 +36,23 @@ Use the provided script in the project root: ### PHP Extensions Required: exif, pdo_mysql +### Third-Party Integration Environment Variables + +Configure these values in the runtime environment instead of committing service credentials: + +| Variable | Purpose | +| --- | --- | +| `GOOGLE_MAPS_API_KEY` | Server-side Google Maps component key | +| `GOOGLE_MAPS_BROWSER_API_KEY` | Browser-facing Google Maps key exposed through app params | +| `RECAPTCHA_SECRET_KEY` | Server-side reCAPTCHA verification secret | +| `JIRA_URL` | Jira instance URL | +| `JIRA_EMAIL` | Jira API account email | +| `JIRA_API_TOKEN` | Jira API token | +| `ALGOLIA_APP_ID` | Algolia application ID | +| `ALGOLIA_API_KEY` | Algolia API key | +| `IPINFO_ACCESS_TOKEN` | IP geolocation lookup token | +| `SLACK_WEBHOOK_URL` | Slack incoming webhook URL | + ### Puppeteer Setup ```bash curl -sL https://deb.nodesource.com/setup_12.x | sudo -E bash - @@ -56,4 +73,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/scripts/check-thirdparty-key-hardening.py b/scripts/check-thirdparty-key-hardening.py new file mode 100755 index 00000000..cfbdc1c1 --- /dev/null +++ b/scripts/check-thirdparty-key-hardening.py @@ -0,0 +1,54 @@ +#!/usr/bin/env python3 +"""Fail if third-party integration credentials are hardcoded in config.""" + +from __future__ import annotations + +import re +import sys +from pathlib import Path + +ROOT = Path(__file__).resolve().parents[1] + +CHECKS = [ + ( + ROOT / "common/config/main.php", + [ + re.compile(r"6L[0-9A-Za-z_-]{30,}"), + re.compile(r"AIza[0-9A-Za-z_-]{20,}"), + re.compile(r"https://hooks\.slack\.com/services/[^'\"\s]+"), + re.compile(r"'apiToken'\s*=>\s*['\"][^'\"]+['\"]"), + re.compile(r"'apiKey'\s*=>\s*['\"][a-f0-9]{24,}['\"]", re.I), + re.compile(r"'accessKey'\s*=>\s*['\"][a-f0-9]{12,}['\"]", re.I), + ], + ), + ( + ROOT / "common/config/params.php", + [ + re.compile(r"AIza[0-9A-Za-z_-]{20,}"), + re.compile(r"'google_api_key'\s*=>\s*['\"][^'\"]+['\"]"), + ], + ), +] + + +def main() -> int: + failures: list[str] = [] + for path, patterns in CHECKS: + text = path.read_text() + for pattern in patterns: + for match in pattern.finditer(text): + line = text.count("\n", 0, match.start()) + 1 + failures.append(f"{path.relative_to(ROOT)}:{line}: {pattern.pattern}") + + if failures: + print("Third-party key hardening check failed:") + for failure in failures: + print(f" - {failure}") + return 1 + + print("Third-party key hardening check passed.") + return 0 + + +if __name__ == "__main__": + sys.exit(main())