feat(launcher,lock): MeowOS 锁屏 4 位 PIN(system.pin 同源面板,错5锁5分钟持久化,唤醒/电源菜单手动锁)

- system.pin:4 位数字 PIN,sha256+salt 存 settings.conf(格式与面板 panel.pin 全等,绝无明文)。
  panel.pin 已设且 system.pin 未设时锁屏接受 panel.pin,首次验证成功后并入 system.pin。
- 锁屏时机:息屏唤醒后(默认开,system.pin_lock_on_wake=1 可关)+ 电源菜单「锁定」手动锁;
  开机不锁(boot 进主屏不拦)。
- 锁屏页:launcher 渲染系统级全屏页,App 不可见不可触;SDK 按钮画数字键盘(不调 IME),
  输入 4 位自动校验;● 遮罩不回显数字;错 5 次锁 5 分钟(持久化锁定戳/计数,重启不清)。
- 安全细节:锁屏页电源键=息屏(允许再睡),音量键不动,不响应左缘返回/通知中心手势。
  兜底:SSH root 删 system.pin 键即解锁(无其它后门)。HibyOS 不涉及。
- 宿主测试(test_lock_screen):设置/校验/错5锁定持久化(重载模拟重启)/唤醒触发/开机不锁
  /panel.pin 迁移,全 PASS;既有 settings_brightness/notif_panel/notif_tf/vol_ramp_jack 回归
  无碍;交叉 -Wall -Wextra 0 warning。meow_launcherd md5 670f978e71c1e81cfe86d47c21248c9d。
This commit is contained in:
AskaEth committed 2026-09-02 00:48:23 +08:00
1 parent 5a5e995ebd
commit e948a0a44e
14 files changed
+1011 -14

No files matched your search

+123
View File
@@ -0,0 +1,123 @@
/* test_lock_screen.c — M6.x 宿主测试:锁屏 4 位 PIN(lock_screen.c 纯逻辑 + 真实 meow_settings 后端)。
*
* 直接 #include "meow_settings.c" + "lock_screen.c" 于同一 TU(同 test_notif_tf.c 手法),以「真实
* settings.conf」验证:设置/校验/错5锁定持久化(重启不清)/唤醒路径触发/panel.pin 迁移。
* 与面板面板访问级 PIN 同格式(`salt:sha256(salt||pin)`),sha256 算法与 meowpanel 逐字一致。
*
* 运行:gcc -D_GNU_SOURCE -DMEOW_SETTINGS_FILE=\"/tmp/meow_lock_test/settings.conf\" \
* -o test_lock_screen test_lock_screen.c mydir? —— 实际在 launcher 目录:
* gcc -D_GNU_SOURCE -DMEOW_SETTINGS_FILE=\"/tmp/meow_lock_test/settings.conf\" \
* -I. -o test_lock_screen test_lock_screen.c && ./test_lock_screen
*/
#define _GNU_SOURCE
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/stat.h>
#include <time.h>
/* 覆盖存储路径到临时目录(需父目录存在;test 内 mkdir) */
#include "meow_settings.c"
#include "lock_screen.c"
static int g_fail = 0;
#define CHECK(cond, msg) do { \
if (!(cond)) { fprintf(stderr, "FAIL: %s (%s:%d)\n", msg, __FILE__, __LINE__); g_fail++; } \
else fprintf(stderr, "ok: %s\n", msg); \
} while (0)
int main(void)
{
const char *conf = MEOW_SETTINGS_FILE;
mkdir("/tmp/meow_lock_test", 0755);
unlink(conf);
unlink("/data/meow_boot_default"); /* 尽力清掉 save 的 boot.default 同步残留(非 root 会失败,无碍) */
/* ---- 初始化(空文件:默认值激活)---- */
CHECK(meow_settings_init() == MEOW_OK, "init (empty conf)");
CHECK(lck_pin_configured() == 0, "no pin configured initially");
CHECK(lck_lock_required(1) == 0, "wake-required=0 when no pin");
/* ---- 设置/校验(lck_pin_set 落盘 + 校验正确/错误)---- */
CHECK(lck_pin_set("1234") == MEOW_OK, "set pin 1234");
CHECK(lck_pin_configured() == 1, "configured after set");
CHECK(lck_lock_required(1) == 1, "wake-required=1 (pin set, wake=1 default)");
CHECK(lck_pin_check("1234") == 1, "check correct pin");
CHECK(lck_pin_check("0000") == 0, "check wrong pin");
CHECK(lck_pin_valid("1234") == 1, "valid 4-digit");
CHECK(lck_pin_valid("12") == 0, "invalid len 2");
CHECK(lck_pin_valid("12a4") == 0, "invalid non-digit");
CHECK(lck_pin_valid("") == 0, "invalid empty");
CHECK(lck_pin_set("12") == MEOW_ERR_INVAL, "reject set non-4-digit");
/* ---- 唤醒路径触发 / 开关 ---- */
CHECK(lck_lock_required(0) == 1, "manual lock(allow_disable=0) always required");
meow_settings_set_int("system.pin_lock_on_wake", 0);
meow_settings_save();
CHECK(lck_lock_required(1) == 0, "wake-required=0 after wake=0");
CHECK(lck_lock_required(0) == 1, "manual still required after wake=0");
meow_settings_set_int("system.pin_lock_on_wake", 1);
meow_settings_save();
CHECK(lck_lock_required(1) == 1, "wake-required=1 after wake=1");
/* 开机不锁是结构性(boot 路径不调 lck_lock_required)——此处断言决策函数正确即隔离该项 */
/* ---- 错 5 次锁定(持久化,重启不清)---- */
CHECK(lck_lock_remaining() == 0, "not locked before fails");
int r1 = lck_pin_fail(); /* 1 */
int r2 = lck_pin_fail(); /* 2 */
int r3 = lck_pin_fail(); /* 3 */
int r4 = lck_pin_fail(); /* 4 */
CHECK(r1 == 0 && r2 == 0 && r3 == 0 && r4 == 0, "first 4 fails not locked");
int r5 = lck_pin_fail(); /* 5 -> lock */
CHECK(r5 > 280 && r5 <= 300, "5th fail locks ~300s");
time_t rem1 = lck_lock_remaining();
CHECK(rem1 > 280 && rem1 <= 300, "lock_remaining reflects lockout");
/* 模拟 launcher 重启(重读 settings.conf)→ 锁定戳持久,不因重启清零 */
meow_settings_shutdown();
CHECK(meow_settings_init() == MEOW_OK, "re-init after shutdown (simulated reboot)");
time_t re = lck_lock_remaining();
CHECK(re > 280 && re <= 300, "lock persists after reboot (persisted)");
/* 锁定期间:正确 PIN 仍被识别(但 UI 层禁 input;此处验证逻辑不因锁定改变凭据) */
CHECK(lck_pin_check("1234") == 1, "correct pin still recognized during lockout");
/* 锁定到期:把截止戳拨到过去 → remaining 自动清 + 清零(进程内解禁) */
meow_settings_set_int("system.pin_lock_until", (int)time(NULL) - 1);
meow_settings_save();
CHECK(lck_lock_remaining() == 0, "expired lock auto-clears");
int fails_now; meow_settings_get_int("system.pin_fails", &fails_now);
CHECK(fails_now == 0, "fail counter cleared after expiry");
/* ---- panel.pin 迁移:system.pin 未设 + panel.pin 已设 → 接受 panel.pin;首成功并入 system.pin ---- */
/* 造一个合法 panel.pin(复用本库的哈希:先 set 得 hash 值,清 system.pin 转写 panel.pin) */
lck_pin_set("5678");
char pphash[MEOW_SET_MAX_LEN];
CHECK(meow_settings_get_str("system.pin", pphash, sizeof pphash) == MEOW_OK, "get system.pin hash");
meow_settings_set_str("system.pin", ""); /* 模拟 system.pin 未设 */
meow_settings_set_str("panel.pin", pphash); /* 面板已设 panel.pin(同 hash 格式) */
meow_settings_save();
CHECK(lck_pin_configured() == 1, "configured via panel.pin only");
CHECK(lck_lock_required(1) == 1, "wake-required via panel.pin");
CHECK(lck_pin_check("5678") == 1, "accept panel.pin when system.pin absent");
CHECK(lck_pin_check("1234") == 0, "reject wrong pin during migration");
/* 首次成功 → 并入 system.pin */
lck_pin_success();
char sp2[MEOW_SET_MAX_LEN];
CHECK(meow_settings_get_str("system.pin", sp2, sizeof sp2) == MEOW_OK && sp2[0], "system.pin set after migrate");
CHECK(strcmp(sp2, pphash) == 0, "system.pin == panel.pin after migrate");
CHECK(lck_pin_check("5678") == 1, "still accept after migrate (via system.pin)");
/* ---- 清除(兜底解锁):lck_pin_clear 后不再要求锁 ---- */
/* lck_pin_clear 只清 system.pin;panel.pin 仍存(迁移源),先清掉再断言全部未配 */
meow_settings_set_str("panel.pin", "");
meow_settings_save();
CHECK(lck_pin_clear() == MEOW_OK, "pin clear");
CHECK(lck_pin_configured() == 0, "not configured after clear");
CHECK(lck_lock_required(1) == 0, "wake-required=0 after clear");
unlink(conf);
printf("\n%s\n", g_fail ? "SOME TESTS FAILED" : "ALL PASS");
return g_fail ? 1 : 0;
}