通用電子投票平台(原院士選舉參考實作)。
Electronic voting platform (general-purpose; originally a reference implementation for academician elections).
Requirements: PHP 8.2+, MariaDB 10.6+, Composer, Apache/Nginx. See SETUP.md for required PHP extensions.
Quick start:
- Clone
main(hasinstall.sh):git clone --branch main --depth 1 https://github.com/AS-ITS/evoting.git
After a release that includes the installer (e.g.v1.0.1+), you may use that tag. Do not usev1.0.0for fresh install (no install script). Do not usecomposer create-project. - Recommended (fresh install): one-liner in SETUP.md (
git clone … && cd … && sudo bash scripts/install.sh). For upgrades — do not re-runinit_db.sql. - Or manually:
composer install --prefer-dist, thenbash scripts/ensure-writable-dirs.sh, copy.env.example→.env, importdocs/init_db.sql,php yii admin/create, point Document Root toweb/
Full install, Web Server samples, and production checklist: SETUP.md (Traditional Chinese).
Architecture notes: docs/ARCHITECTURE.md. Security reporting: SECURITY.md.
Vote types: open ballot (no auth) and anonymous (one-time passwords). Maintenance status: see GOVERNANCE.md. Licensed under MIT (LICENSE). Report vulnerabilities via SECURITY.md.
專案目前由中央研究院資訊服務處人員維護,不構成服務等級或永久維護承諾。詳見 GOVERNANCE.md。
- 請 clone
main(含install.sh):git clone --branch main --depth 1 https://github.com/AS-ITS/evoting.git
待有含安裝精靈的 release(如v1.0.1+)再改用該 tag。勿用v1.0.0新裝。不要使用composer create-project - 建議新裝:見 SETUP.md 一行指令(
git clone … && cd … && sudo bash scripts/install.sh)。升級勿再跑 init_db - 或手動:
composer install --prefer-dist→bash scripts/ensure-writable-dirs.sh→ 設定.env→ 匯入docs/init_db.sql→php yii admin/create→ Document Root 指向web/
完整安裝、Web Server 設定與正式環境檢查表見 SETUP.md。
系統架構與開發指引見 docs/ARCHITECTURE.md。
- 登入:
/auth/login或/admin - 登出:
/auth/logout - 修改密碼:
/auth/change-password - 忘記密碼:
/auth/forgot-password(帳號須先設定信箱;非正式環境信件寫入runtime/mail)
管理員可透過「修改密碼」功能更新自己的登入密碼。
密碼要求:
- 長度至少 8 個字元
- 必須包含至少一個字母和一個數字
- 不可與帳號相同
- 不可與目前密碼相同
安全特性:
- 驗證舊密碼正確性
- 密碼強度檢查
- 防止密碼重用
- 操作日誌記錄(LOG 418)
- 修改成功後自動登出,要求重新登入
忘記密碼(/auth/forgot-password):帳號須先設定信箱。連結 30 分鐘、單次;不關閉 TOTP。正式環境經 SMTP 寄出(LOG 425/426);其他環境寫入 runtime/mail/。升級既有資料庫須執行 docs/migrations/20261021_password_reset.sql。詳見 SETUP.md。
- TOTP 綁定:登入後台 → 使用者管理 → 雙因素驗證(
/users/totp) - 敏感操作(密碼 CSV 匯出、RBAC 同步):需輸入管理員密碼;已啟用 TOTP 者另需 6 碼
- 詳見 SECURITY.md、SETUP.md §二次驗證與 TOTP
bash scripts/open-source-prep.sh單元測試直接呼叫 Model 方法,不需要測試伺服器。Fixture 由各測試自動管理。
# 步驟 1:清除舊測試資料(確保乾淨起始狀態)
echo "yes" | php yii fixture/unload "*" --appconfig=config/console-test.php
# 步驟 2:執行所有單元測試
php vendor/bin/codecept run unit
# 執行特定測試檔案
php vendor/bin/codecept run unit models/FormPartiesTest
# 顯示詳細輸出
php vendor/bin/codecept run unit --debug注意:單元測試執行後會清除 Config、Users、Rbac 等資料表,若需接著執行驗收或功能測試,需重新載入所有 Fixture。
功能測試透過 Codeception Yii2 模組模擬 HTTP 請求,直接測試 Controller 行為,不需要啟動測試伺服器。Fixture 由各 Cest 類別的 _fixtures() 方法自動管理,每個測試方法執行前會自動載入。
共 190 個測試,涵蓋 19 個 Controller/場景(詳見 tests/TEST_STATUS.md):
| Cest 檔案 | 測試範圍 |
|---|---|
AuthControllerCest |
登入、登出、修改密碼 |
BallotControllerCest |
選票管理 |
BallotWorkControllerCest |
投票工作管理 |
CandiControllerCest |
候選人設定 |
CountControllerCest |
開票作業 |
ElectControllerCest |
投票場次管理 |
GroupControllerCest |
群組管理 |
GroupMemberControllerCest |
群組成員管理 |
ManageControllerCest |
系統管理 |
PasswdControllerCest |
匿名投票密碼管理 |
PermissionDenialCest |
權限控制驗證(各角色存取) |
QuestionControllerCest |
投票問題管理 |
ResultControllerCest |
開票結果 |
RoundControllerCest |
輪次管理 |
SiteControllerCest |
網站首頁 |
UsersControllerCest |
使用者管理 |
VoteControllerCest |
投票操作 |
VoteListCest |
投票列表 |
VoteResultCest |
投票結果頁 |
執行方式:
# 執行所有功能測試
php vendor/bin/codecept run functional
# 執行特定 Cest 檔案
php vendor/bin/codecept run functional ElectControllerCest
# 執行特定測試方法
php vendor/bin/codecept run functional ElectControllerCest:testCreateVotePageDisplay
# 顯示詳細輸出
php vendor/bin/codecept run functional --debug首次執行前:先以測試設定載入必要 fixture;測試失敗不應以重跑掩蓋,請保留輸出並排查根因。
echo "yes" | php yii fixture/load "Votes,Parties,Round,Questions,CandiData,Passwords,CandiConfig,Config,Users,Rbac,Group,GroupMember,Ballots,BallotsSelected,ResultsConfig" --appconfig=config/console-test.php php vendor/bin/codecept run functional
驗收測試透過瀏覽器模擬完整操作流程,需先啟動測試伺服器並載入所有 Fixture。
# 步驟 1:啟動測試伺服器(在獨立終端機中執行,保持執行)
# 測試入口僅在 APP_ENV=testing 時啟用;.env 為 development/production 時須如下指定,否則一律回 404
APP_ENV=testing php -S localhost:8080 -t web web/router-test.php
# 步驟 2:載入所有 Fixture(必須包含 Config、Users、Rbac)
echo "yes" | php yii fixture/load "Votes,Parties,Round,Questions,CandiData,Passwords,CandiConfig,Config,Users,Rbac,Group,GroupMember,Ballots,BallotsSelected,ResultsConfig" --appconfig=config/console-test.php
# 步驟 3:執行所有驗收測試
php vendor/bin/codecept run acceptance
# 執行特定測試
php vendor/bin/codecept run acceptance AnonVoteCest
# 步驟 4:重複測試前,重新執行步驟 2 即可將測試資料還原為初始狀態注意:
fixture/unload會連同相依的 Fixture 一起清除。例如fixture/unload "Ballots,BallotsSelected"也會清空CandiData、Questions、Votes(BallotsSelected相依CandiData/Questions,CandiData相依Votes),之後的測試會因缺少投票資料而失敗。重設資料請用fixture/load。
--appconfig=config/console-test.php 參數,確保操作測試資料庫而非正式資料庫。
以 Headless Chrome 實際操作畫面(全畫面巡檢、對話框、附件與照片、投票流程),不需安裝 Node.js。測試伺服器須以 APP_ENV=testing 啟動並已載入 fixture:
APP_ENV=testing php -S localhost:8080 -t web web/router-test.php
php tests/e2e/run.php# 產生預期的測試資料: 從 /tests/fixtures/data 修改
php yii fixture/load "*" --appconfig=config/console-test.php
# 透過 template 產生測試資料
php yii fixture/generate <fixtures> --count=<number> --appconfig=config/console-test.php# 清除所有測試資料
php yii fixture/unload "*" --appconfig=config/console-test.php
# 清除特定測試資料(會連同相依的 Fixture 一起清除,見上方注意事項)
php yii fixture/unload "Ballots,BallotsSelected" --appconfig=config/console-test.phpphp ./vendor/bin/codecept run acceptance AnonVoteCest.php
只執行tryAnonVoteCandidates,其他@skip;然後開n個cmd,更改anonProvider()中的密碼清單(limit、offset),同時執行php ./vendor/bin/codecept run acceptance AnonVoteCest.php,觀察結果。
ex:
cmd1: offset(0),執行php ./vendor/bin/codecept run acceptance AnonVoteCest.php
cmd2: offset(100),執行php ./vendor/bin/codecept run acceptance AnonVoteCest.php
以此類推....
本專案提供符合 CycloneDX 1.5 標準的 S-BOM 資料,用於軟體供應鏈安全與依賴管理。
- sbom-vendor.json: 後端 PHP 依賴 (Composer) 的完整清單。
- sbom-frontend.json: 前端 JavaScript 函式庫 (Bootstrap 等) 的完整清單。
專案內含一個獨立的 PHP 腳本,無需安裝任何額外套件即可讀取專案狀態並產生最新的 S-BOM。
執行方式:
# 產生所有 S-BOM (後端與前端)
php docs/generate_sbom.php all
# 僅產生後端 S-BOM
php docs/generate_sbom.php vendor
# 僅產生前端 S-BOM
php docs/generate_sbom.php frontend- docs/ARCHITECTURE.md - 系統架構與開發指引
- SETUP.md - 環境設定指南
- docs/CONFIGURATION.md - 系統配置完整說明
- docs/MASTER_KEY_SETUP.md - 主金鑰設定指南
- docs/KEY_DERIVATION_RULES.md - 金鑰衍生規則
- tests/README.md - 測試文件索引
- tests/TEST_GUIDE.md - 測試撰寫指南
- tests/TEST_STATUS.md - 最近驗證結果與已知限制
tests/
├── unit/
│ └── controllers/
│ └── AuthControllerTest.php # 管理員認證單元測試(含密碼修改)
└── acceptance/
└── ChangePasswordCest.php # 密碼修改功能測試(9 個場景)
- 正式環境:
php yii fixture/load→ 使用config/console.php→ 操作正式資料庫voting - 測試環境:
php yii fixture/load --appconfig=config/console-test.php→ 使用config/console-test.php→ 操作測試資料庫voting_test
務必使用測試配置避免影響正式資料!
Users 模型使用雙欄位設計:
password- 資料庫欄位(以password_hash()單向雜湊儲存,不可還原)password_plain- 虛擬屬性(表單輸入/驗證用)
正確的密碼更新方式:
// ✅ 正確
$user->password_plain = '新密碼';
$user->save(); // beforeSave() 自動雜湊
// ❌ 錯誤
$user->password = $user->hashPassword('新密碼');
$user->save(false); // beforeSave() 可能用舊 password_plain 覆蓋漸進式遷移:validatePassword() 會先以 password_verify() 驗證;
若資料庫仍是舊制 AES 可逆密文,驗證成功後會自動轉為雜湊寫回,無須一次性重設全部帳號。
詳見 models/Users.php 的 beforeSave() 方法。
- 執行環境:
web/index.php由環境變數YII_DEBUG/YII_ENV控制,未設定時預設為正式環境(prod、除錯關閉)。開發環境請在.env設定YII_DEBUG=true、YII_ENV=dev。 - 測試入口:
web/index-test.php、web/router-test.php僅在明確的APP_ENV=testing/test下啟用。正式部署仍建議由 Web Server 拒絕這兩個路徑,或在部署包排除。 - 初始管理員:匯入
docs/init_db.sql後執行php yii admin/create建立admin(sa)帳號;密碼由安裝時互動設定,不寫入文件。 - 上傳目錄:檔案上傳目錄(
APP_PATH_UPLOADS,預設/var/www/filepool)必須位於網站根目錄之外;若因故置於網站根目錄下,請停用該目錄的 PHP 執行:
# Apache(上傳目錄的 .htaccess)
<FilesMatch "\.ph(p[3457]?|t|tml)$">
Require all denied
</FilesMatch># nginx
location ~* ^/uploads/.*\.php$ {
deny all;
}| 文件 | 用途 |
|---|---|
| CHANGELOG.md | 版本變更紀錄(Keep a Changelog) |
| SETUP.md | 安裝、部署、測試環境、部署最佳實踐 |
| SECURITY.md | 資安政策、TOTP、開源釋出前檢查 |
| CONTRIBUTING.md | Issue/PR 與測試流程 |
| CODE_OF_CONDUCT.md | 行為準則 |
| GOVERNANCE.md | 維護狀態與決策 |
| docs/ARCHITECTURE.md | 系統架構與開發指引 |
| docs/RELEASING.md | 公開版本發布指南 |
| docs/threat-model/README.md | 威脅建模(STRIDE/匿名性) |
| docs/CONFIGURATION.md | 環境變數與配置詳解 |
| LICENSE / NOTICE | MIT 授權與第三方聲明 |
| docs/授權合規評估檢核表.md | 授權合規檢核表 |
| OPENSOURCE_MIGRATION.md | 通用化遷移摘要 |
回報問題:一般問題開 GitHub Issue(見模板);提交前請先查 SETUP.md 常見問題與 runtime/logs/,並附上 PHP、MariaDB、APP_ENV。安全漏洞請勿在公開 Issue 揭露,見 SECURITY.md。
程式碼貢獻:見 CONTRIBUTING.md。
本專案原始碼以 MIT License 釋出。第三方套件見 NOTICE 與 docs/授權合規評估檢核表.md。