Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 6 additions & 2 deletions cmd/common.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,13 +20,17 @@ func Init() {

if v3_46_0.IsLegacyRoleDetected() {
utils.Log.Warnf("Detected legacy role format, executing ConvertLegacyRoles patch early...")
v3_46_0.ConvertLegacyRoles()
if err := v3_46_0.ConvertLegacyRoles(); err != nil {
utils.Log.Fatalf("Failed to convert legacy roles: %v", err)
}
}

data.InitData()
bootstrap.InitStreamLimit()
bootstrap.InitIndex()
bootstrap.InitUpgradePatch()
if err := bootstrap.InitUpgradePatch(); err != nil {
utils.Log.Fatalf("Failed to apply upgrade patches: %v", err)
}
}

func Release() {
Expand Down
3 changes: 0 additions & 3 deletions internal/bootstrap/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -51,9 +51,6 @@ func InitConfig() {
log.Fatalf("load config error: %+v", err)
}
LastLaunchedVersion = conf.Conf.LastLaunchedVersion
if strings.HasPrefix(conf.Version, "v") || LastLaunchedVersion == "" {
conf.Conf.LastLaunchedVersion = conf.Version
}
// update config.json struct
confBody, err := utils.Json.MarshalIndent(conf.Conf, "", " ")
if err != nil {
Expand Down
2 changes: 1 addition & 1 deletion internal/bootstrap/data/dev.go
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ func initDevData() {
err = db.CreateUser(&model.User{
Username: "Noah",
Password: "hsu",
BasePath: "/data",
BasePath: "/",
Role: nil,
Permission: 512,
})
Expand Down
4 changes: 2 additions & 2 deletions internal/bootstrap/data/setting.go
Original file line number Diff line number Diff line change
Expand Up @@ -224,7 +224,7 @@ func InitialSettings() []model.SettingItem {
{Key: conf.SSOJwtPublicKey, Value: "", Type: conf.TypeString, Group: model.SSO, Flag: model.PRIVATE},
{Key: conf.SSOExtraScopes, Value: "", Type: conf.TypeString, Group: model.SSO, Flag: model.PRIVATE},
{Key: conf.SSOAutoRegister, Value: "false", Type: conf.TypeBool, Group: model.SSO, Flag: model.PRIVATE},
{Key: conf.SSODefaultDir, Value: "/", Type: conf.TypeString, Group: model.SSO, Flag: model.PRIVATE},
{Key: conf.SSODefaultDir, Value: "/", Type: conf.TypeString, Group: model.SSO, Flag: model.DEPRECATED},
{Key: conf.SSODefaultPermission, Value: "0", Type: conf.TypeNumber, Group: model.SSO, Flag: model.PRIVATE},
{Key: conf.SSOCompatibilityMode, Value: "false", Type: conf.TypeBool, Group: model.SSO, Flag: model.PUBLIC},

Expand All @@ -235,7 +235,7 @@ func InitialSettings() []model.SettingItem {
{Key: conf.LdapManagerPassword, Value: "", Type: conf.TypeString, Group: model.LDAP, Flag: model.PRIVATE},
{Key: conf.LdapUserSearchBase, Value: "", Type: conf.TypeString, Group: model.LDAP, Flag: model.PRIVATE},
{Key: conf.LdapUserSearchFilter, Value: "(uid=%s)", Type: conf.TypeString, Group: model.LDAP, Flag: model.PRIVATE},
{Key: conf.LdapDefaultDir, Value: "/", Type: conf.TypeString, Group: model.LDAP, Flag: model.PRIVATE},
{Key: conf.LdapDefaultDir, Value: "/", Type: conf.TypeString, Group: model.LDAP, Flag: model.DEPRECATED},
{Key: conf.LdapDefaultPermission, Value: "0", Type: conf.TypeNumber, Group: model.LDAP, Flag: model.PRIVATE},
{Key: conf.LdapLoginTips, Value: "login with ldap", Type: conf.TypeString, Group: model.LDAP, Flag: model.PUBLIC},

Expand Down
115 changes: 86 additions & 29 deletions internal/bootstrap/patch.go
Original file line number Diff line number Diff line change
@@ -1,24 +1,30 @@
package bootstrap

import (
"encoding/json"
"fmt"
"os"
"path/filepath"
"strings"

"github.com/alist-org/alist/v3/cmd/flags"
"github.com/alist-org/alist/v3/internal/bootstrap/patch"
"github.com/alist-org/alist/v3/internal/conf"
"github.com/alist-org/alist/v3/pkg/utils"
"strings"
)

var LastLaunchedVersion = ""

func safeCall(v string, i int, f func()) {
func safeCall(v string, i int, f func() error) (err error) {
defer func() {
if r := recover(); r != nil {
utils.Log.Errorf("Recovered from patch (version: %s, index: %d) panic: %v", v, i, r)
err = fmt.Errorf("patch %s[%d] panicked: %v", v, i, r)
}
}()

f()
if err := f(); err != nil {
return fmt.Errorf("patch %s[%d]: %w", v, i, err)
}
return nil
}

func getVersion(v string) (major, minor, patchNum int, err error) {
Expand All @@ -33,42 +39,93 @@ func compareVersion(majorA, minorA, patchNumA, majorB, minorB, patchNumB int) bo
if minorA != minorB {
return minorA > minorB
}
if patchNumA != patchNumB {
return patchNumA > patchNumB
}
return true
return patchNumA >= patchNumB
}

func InitUpgradePatch() {
if !strings.HasPrefix(conf.Version, "v") {
for _, vp := range patch.UpgradePatches {
for i, p := range vp.Patches {
safeCall(vp.Version, i, p)
}
}
return
func InitUpgradePatch() error {
release := strings.HasPrefix(conf.Version, "v")
if release && LastLaunchedVersion == conf.Version {
return nil
}
if LastLaunchedVersion == conf.Version {
return
previous := LastLaunchedVersion
if previous == "" {
previous = "v0.0.0"
}
if LastLaunchedVersion == "" {
LastLaunchedVersion = "v0.0.0"
}
major, minor, patchNum, err := getVersion(LastLaunchedVersion)
major, minor, patchNum, err := getVersion(previous)
if err != nil {
utils.Log.Warnf("Failed to parse last launched version %s: %v, skipping all patches and rewrite last launched version", LastLaunchedVersion, err)
return
// Development builds can predate any migration. Replay idempotent
// patches rather than marking an unknown database as already upgraded.
utils.Log.Warnf("Cannot parse last launched version %q; checking all upgrade patches", previous)
major, minor, patchNum = 0, 0, 0
}
for _, vp := range patch.UpgradePatches {
ma, mi, pn, err := getVersion(vp.Version)
if err != nil {
utils.Log.Errorf("Skip invalid version %s patches: %v", vp.Version, err)
continue
return fmt.Errorf("invalid patch version %s: %w", vp.Version, err)
}
if compareVersion(ma, mi, pn, major, minor, patchNum) {
if !release || compareVersion(ma, mi, pn, major, minor, patchNum) {
for i, p := range vp.Patches {
safeCall(vp.Version, i, p)
if err := safeCall(vp.Version, i, p); err != nil {
return err
}
}
}
}
if release {
return recordLaunchedVersion()
}
return nil
}

// Persist only the version field from the on-disk config. Runtime config may
// contain environment overrides and must not be written back here.
func recordLaunchedVersion() error {
configPath := filepath.Join(flags.DataDir, "config.json")
body, err := os.ReadFile(configPath)
if err != nil {
return err
}
var fields map[string]json.RawMessage
if err := json.Unmarshal(body, &fields); err != nil {
return err
}
if fields == nil {
return fmt.Errorf("invalid config object in %s", configPath)
}
fields["last_launched_version"], err = json.Marshal(conf.Version)
if err != nil {
return err
}
body, err = json.MarshalIndent(fields, "", " ")
if err != nil {
return err
}
info, err := os.Stat(configPath)
if err != nil {
return err
}
tmp, err := os.CreateTemp(filepath.Dir(configPath), ".config-upgrade-*")
if err != nil {
return err
}
defer os.Remove(tmp.Name())
if err = tmp.Chmod(info.Mode().Perm()); err == nil {
_, err = tmp.Write(body)
}
if err == nil {
err = tmp.Sync()
}
closeErr := tmp.Close()
if err != nil {
return err
}
if closeErr != nil {
return closeErr
}
if err := os.Rename(tmp.Name(), configPath); err != nil {
return err
}
conf.Conf.LastLaunchedVersion = conf.Version
LastLaunchedVersion = conf.Version
return nil
}
17 changes: 12 additions & 5 deletions internal/bootstrap/patch/all.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,38 +5,45 @@ import (
"github.com/alist-org/alist/v3/internal/bootstrap/patch/v3_32_0"
"github.com/alist-org/alist/v3/internal/bootstrap/patch/v3_41_0"
"github.com/alist-org/alist/v3/internal/bootstrap/patch/v3_46_0"
"github.com/alist-org/alist/v3/internal/bootstrap/patch/v3_64_0"
)

type VersionPatches struct {
// Version means if the system is upgraded from Version or an earlier one
// to the current version, all patches in Patches will be executed.
Version string
Patches []func()
Patches []func() error
}

var UpgradePatches = []VersionPatches{
{
Version: "v3.24.0",
Patches: []func(){
Patches: []func() error{
v3_24_0.HashPwdForOldVersion,
},
},
{
Version: "v3.32.0",
Patches: []func(){
Patches: []func() error{
v3_32_0.UpdateAuthnForOldVersion,
},
},
{
Version: "v3.41.0",
Patches: []func(){
Patches: []func() error{
v3_41_0.GrantAdminPermissions,
},
},
{
Version: "v3.46.0",
Patches: []func(){
Patches: []func() error{
v3_46_0.ConvertLegacyRoles,
},
},
{
Version: "v3.64.0",
Patches: []func() error{
v3_64_0.ResetUserBasePaths,
},
},
}
9 changes: 5 additions & 4 deletions internal/bootstrap/patch/v3_24_0/hash_password.go
Original file line number Diff line number Diff line change
@@ -1,26 +1,27 @@
package v3_24_0

import (
"fmt"
"github.com/alist-org/alist/v3/internal/db"
"github.com/alist-org/alist/v3/internal/op"
"github.com/alist-org/alist/v3/pkg/utils"
)

// HashPwdForOldVersion encode passwords using SHA256
// First published: 75acbcc perf: sha256 for user's password (close #3552) by Andy Hsu
func HashPwdForOldVersion() {
func HashPwdForOldVersion() error {
users, _, err := op.GetUsers(1, -1)
if err != nil {
utils.Log.Fatalf("[hash pwd for old version] failed get users: %v", err)
return fmt.Errorf("hash passwords: get users: %w", err)
}
for i := range users {
user := users[i]
if user.PwdHash == "" {
user.SetPassword(user.Password)
user.Password = ""
if err := db.UpdateUser(&user); err != nil {
utils.Log.Fatalf("[hash pwd for old version] failed update user: %v", err)
return fmt.Errorf("hash passwords: update user: %w", err)
}
}
}
return nil
}
9 changes: 5 additions & 4 deletions internal/bootstrap/patch/v3_32_0/update_authn.go
Original file line number Diff line number Diff line change
@@ -1,25 +1,26 @@
package v3_32_0

import (
"fmt"
"github.com/alist-org/alist/v3/internal/db"
"github.com/alist-org/alist/v3/internal/op"
"github.com/alist-org/alist/v3/pkg/utils"
)

// UpdateAuthnForOldVersion updates users' authn
// First published: bdfc159 fix: webauthn logspam (#6181) by itsHenry
func UpdateAuthnForOldVersion() {
func UpdateAuthnForOldVersion() error {
users, _, err := op.GetUsers(1, -1)
if err != nil {
utils.Log.Fatalf("[update authn for old version] failed get users: %v", err)
return fmt.Errorf("update authn: get users: %w", err)
}
for i := range users {
user := users[i]
if user.Authn == "" {
user.Authn = "[]"
if err := db.UpdateUser(&user); err != nil {
utils.Log.Fatalf("[update authn for old version] failed update user: %v", err)
return fmt.Errorf("update authn: update user: %w", err)
}
}
}
return nil
}
9 changes: 3 additions & 6 deletions internal/bootstrap/patch/v3_41_0/grant_permission.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,20 +2,17 @@ package v3_41_0

import (
"github.com/alist-org/alist/v3/internal/op"
"github.com/alist-org/alist/v3/pkg/utils"
)

// GrantAdminPermissions gives admin Permission 0(can see hidden) - 9(webdav manage) and
// 12(can read archives) - 13(can decompress archives)
// This patch is written to help users upgrading from older version better adapt to PR AlistGo/alist#7705 and
// PR AlistGo/alist#7817.
func GrantAdminPermissions() {
func GrantAdminPermissions() error {
admin, err := op.GetAdmin()
if err == nil && (admin.Permission & 0x33FF) == 0 {
if err == nil && (admin.Permission&0x33FF) == 0 {
admin.Permission |= 0x33FF
err = op.UpdateUser(admin)
}
if err != nil {
utils.Log.Errorf("Cannot grant permissions to admin: %v", err)
}
return err
}
Loading
Loading