mirror of
https://github.com/sipeed/picoclaw.git
synced 2026-06-12 18:08:54 +00:00
71c877a67f
- replace token-based launcher auth with password-based login and sessions - migrate legacy launcher_token values into bcrypt-backed password storage - add one-shot local auto-login bootstrap - update config UI, i18n strings, docs, and auth-related tests
136 lines
3.8 KiB
Go
136 lines
3.8 KiB
Go
package launcherconfig
|
|
|
|
import (
|
|
"context"
|
|
"errors"
|
|
"os"
|
|
"path/filepath"
|
|
"testing"
|
|
)
|
|
|
|
type stubMigrationPasswordStore struct {
|
|
initialized bool
|
|
password string
|
|
}
|
|
|
|
func (s *stubMigrationPasswordStore) IsInitialized(context.Context) (bool, error) {
|
|
return s.initialized, nil
|
|
}
|
|
|
|
func (s *stubMigrationPasswordStore) SetPassword(_ context.Context, plain string) error {
|
|
s.password = plain
|
|
s.initialized = true
|
|
return nil
|
|
}
|
|
|
|
func TestMigrateLegacyLauncherToken(t *testing.T) {
|
|
dir := t.TempDir()
|
|
launcherPath := filepath.Join(dir, FileName)
|
|
cfg := Config{
|
|
Port: DefaultPort,
|
|
LegacyLauncherToken: "legacy-password",
|
|
}
|
|
if err := os.WriteFile(
|
|
launcherPath,
|
|
[]byte("{\n \"port\": 18800,\n \"launcher_token\": \"legacy-password\"\n}\n"),
|
|
0o600,
|
|
); err != nil {
|
|
t.Fatalf("WriteFile() error = %v", err)
|
|
}
|
|
|
|
store := NewPasswordStore(launcherPath, Default())
|
|
result, err := MigrateLegacyLauncherToken(context.Background(), store, launcherPath, cfg)
|
|
if err != nil {
|
|
t.Fatalf("MigrateLegacyLauncherToken() error = %v", err)
|
|
}
|
|
if !result.Migrated {
|
|
t.Fatal("MigrateLegacyLauncherToken().Migrated = false, want true")
|
|
}
|
|
if result.CleanupErr != nil {
|
|
t.Fatalf("MigrateLegacyLauncherToken().CleanupErr = %v, want nil", result.CleanupErr)
|
|
}
|
|
|
|
loaded, err := Load(launcherPath, Default())
|
|
if err != nil {
|
|
t.Fatalf("Load() error = %v", err)
|
|
}
|
|
if loaded.LegacyLauncherToken != "" {
|
|
t.Fatalf("legacy launcher token = %q, want empty", loaded.LegacyLauncherToken)
|
|
}
|
|
if loaded.DashboardPasswordHash == "" {
|
|
t.Fatal("dashboard password hash should be set after migration")
|
|
}
|
|
ok, err := store.VerifyPassword(context.Background(), "legacy-password")
|
|
if err != nil {
|
|
t.Fatalf("VerifyPassword() error = %v", err)
|
|
}
|
|
if !ok {
|
|
t.Fatal("VerifyPassword() = false, want true")
|
|
}
|
|
}
|
|
|
|
func TestMigrateLegacyLauncherTokenCleanupFailureIsNonFatal(t *testing.T) {
|
|
dir := t.TempDir()
|
|
launcherPath := filepath.Join(dir, FileName)
|
|
cfg := Config{
|
|
Port: DefaultPort,
|
|
LegacyLauncherToken: "legacy-password",
|
|
}
|
|
if err := os.WriteFile(
|
|
launcherPath,
|
|
[]byte("{\n \"port\": 18800,\n \"launcher_token\": \"legacy-password\"\n}\n"),
|
|
0o600,
|
|
); err != nil {
|
|
t.Fatalf("WriteFile() error = %v", err)
|
|
}
|
|
|
|
store := &stubMigrationPasswordStore{}
|
|
origSave := saveConfigForMigration
|
|
saveConfigForMigration = func(string, Config) error {
|
|
return errors.New("write launcher config")
|
|
}
|
|
t.Cleanup(func() {
|
|
saveConfigForMigration = origSave
|
|
})
|
|
|
|
result, err := MigrateLegacyLauncherToken(context.Background(), store, launcherPath, cfg)
|
|
if err != nil {
|
|
t.Fatalf("MigrateLegacyLauncherToken() error = %v, want nil", err)
|
|
}
|
|
if !result.Migrated {
|
|
t.Fatal("MigrateLegacyLauncherToken().Migrated = false, want true")
|
|
}
|
|
if result.CleanupErr == nil {
|
|
t.Fatal("MigrateLegacyLauncherToken().CleanupErr = nil, want non-nil")
|
|
}
|
|
if store.password != "legacy-password" {
|
|
t.Fatalf("password = %q, want legacy-password", store.password)
|
|
}
|
|
|
|
loaded, err := Load(launcherPath, Default())
|
|
if err != nil {
|
|
t.Fatalf("Load() error = %v", err)
|
|
}
|
|
if loaded.LegacyLauncherToken != "legacy-password" {
|
|
t.Fatalf(
|
|
"legacy launcher token = %q, want legacy-password after cleanup failure",
|
|
loaded.LegacyLauncherToken,
|
|
)
|
|
}
|
|
}
|
|
|
|
func TestMigrateLegacyLauncherTokenNoopWithoutToken(t *testing.T) {
|
|
launcherPath := filepath.Join(t.TempDir(), FileName)
|
|
store := NewPasswordStore(launcherPath, Default())
|
|
result, err := MigrateLegacyLauncherToken(context.Background(), store, launcherPath, Default())
|
|
if err != nil {
|
|
t.Fatalf("MigrateLegacyLauncherToken() error = %v", err)
|
|
}
|
|
if result.Migrated {
|
|
t.Fatal("MigrateLegacyLauncherToken().Migrated = true, want false")
|
|
}
|
|
if result.CleanupErr != nil {
|
|
t.Fatalf("MigrateLegacyLauncherToken().CleanupErr = %v, want nil", result.CleanupErr)
|
|
}
|
|
}
|