feat: add password auth flag

pull/3750/head
Steven 10 months ago
parent b9006f8ce0
commit 8bf7cdfd31

@ -14,6 +14,7 @@ import (
"github.com/usememos/memos/server" "github.com/usememos/memos/server"
"github.com/usememos/memos/server/profile" "github.com/usememos/memos/server/profile"
"github.com/usememos/memos/server/version"
"github.com/usememos/memos/store" "github.com/usememos/memos/store"
"github.com/usememos/memos/store/db" "github.com/usememos/memos/store/db"
) )
@ -30,13 +31,6 @@ const (
) )
var ( var (
mode string
addr string
port int
data string
driver string
dsn string
public bool
instanceProfile *profile.Profile instanceProfile *profile.Profile
rootCmd = &cobra.Command{ rootCmd = &cobra.Command{
@ -47,26 +41,26 @@ var (
dbDriver, err := db.NewDBDriver(instanceProfile) dbDriver, err := db.NewDBDriver(instanceProfile)
if err != nil { if err != nil {
cancel() cancel()
slog.Error("failed to create db driver", err) slog.Error("failed to create db driver", "error", err)
return return
} }
if err := dbDriver.Migrate(ctx); err != nil { if err := dbDriver.Migrate(ctx); err != nil {
cancel() cancel()
slog.Error("failed to migrate database", err) slog.Error("failed to migrate database", "error", err)
return return
} }
storeInstance := store.New(dbDriver, instanceProfile) storeInstance := store.New(dbDriver, instanceProfile)
if err := storeInstance.MigrateManually(ctx); err != nil { if err := storeInstance.MigrateManually(ctx); err != nil {
cancel() cancel()
slog.Error("failed to migrate manually", err) slog.Error("failed to migrate manually", "error", err)
return return
} }
s, err := server.NewServer(ctx, instanceProfile, storeInstance) s, err := server.NewServer(ctx, instanceProfile, storeInstance)
if err != nil { if err != nil {
cancel() cancel()
slog.Error("failed to create server", err) slog.Error("failed to create server", "error", err)
return return
} }
@ -78,7 +72,7 @@ var (
if err := s.Start(ctx); err != nil { if err := s.Start(ctx); err != nil {
if err != http.ErrServerClosed { if err != http.ErrServerClosed {
slog.Error("failed to start server", err) slog.Error("failed to start server", "error", err)
cancel() cancel()
} }
} }
@ -102,15 +96,14 @@ func Execute() error {
} }
func init() { func init() {
cobra.OnInitialize(initConfig) rootCmd.PersistentFlags().String("mode", "demo", `mode of server, can be "prod" or "dev" or "demo"`)
rootCmd.PersistentFlags().String("addr", "", "address of server")
rootCmd.PersistentFlags().StringVarP(&mode, "mode", "m", "demo", `mode of server, can be "prod" or "dev" or "demo"`) rootCmd.PersistentFlags().Int("port", 8081, "port of server")
rootCmd.PersistentFlags().StringVarP(&addr, "addr", "a", "", "address of server") rootCmd.PersistentFlags().String("data", "", "data directory")
rootCmd.PersistentFlags().IntVarP(&port, "port", "p", 8081, "port of server") rootCmd.PersistentFlags().String("driver", "sqlite", "database driver")
rootCmd.PersistentFlags().StringVarP(&data, "data", "d", "", "data directory") rootCmd.PersistentFlags().String("dsn", "", "database source name(aka. DSN)")
rootCmd.PersistentFlags().StringVarP(&driver, "driver", "", "", "database driver") rootCmd.PersistentFlags().Bool("public", false, "")
rootCmd.PersistentFlags().StringVarP(&dsn, "dsn", "", "", "database source name(aka. DSN)") rootCmd.PersistentFlags().Bool("password-auth", true, "")
rootCmd.PersistentFlags().BoolVarP(&public, "public", "", false, "")
err := viper.BindPFlag("mode", rootCmd.PersistentFlags().Lookup("mode")) err := viper.BindPFlag("mode", rootCmd.PersistentFlags().Lookup("mode"))
if err != nil { if err != nil {
@ -140,22 +133,32 @@ func init() {
if err != nil { if err != nil {
panic(err) panic(err)
} }
err = viper.BindPFlag("password-auth", rootCmd.PersistentFlags().Lookup("password-auth"))
if err != nil {
panic(err)
}
viper.SetDefault("mode", "demo") viper.SetDefault("mode", "demo")
viper.SetDefault("driver", "sqlite") viper.SetDefault("driver", "sqlite")
viper.SetDefault("addr", "") viper.SetDefault("addr", "")
viper.SetDefault("port", 8081) viper.SetDefault("port", 8081)
viper.SetDefault("public", false) viper.SetDefault("public", false)
viper.SetDefault("password-auth", true)
viper.SetEnvPrefix("memos") viper.SetEnvPrefix("memos")
}
func initConfig() { instanceProfile = &profile.Profile{
viper.AutomaticEnv() Mode: viper.GetString("mode"),
var err error Addr: viper.GetString("addr"),
instanceProfile, err = profile.GetProfile() Port: viper.GetInt("port"),
if err != nil { Data: viper.GetString("data"),
slog.Error("failed to get profile", err) Driver: viper.GetString("driver"),
return DSN: viper.GetString("dsn"),
Public: viper.GetBool("public"),
PasswordAuth: viper.GetBool("password-auth"),
Version: version.GetCurrentVersion(viper.GetString("mode")),
}
if err := instanceProfile.Validate(); err != nil {
panic(err)
} }
fmt.Printf(`--- fmt.Printf(`---
@ -167,9 +170,10 @@ addr: %s
port: %d port: %d
mode: %s mode: %s
public: %t public: %t
password-auth: %t
driver: %s driver: %s
--- ---
`, instanceProfile.Version, instanceProfile.Data, instanceProfile.DSN, instanceProfile.Addr, instanceProfile.Port, instanceProfile.Mode, instanceProfile.Public, instanceProfile.Driver) `, instanceProfile.Version, instanceProfile.Data, instanceProfile.DSN, instanceProfile.Addr, instanceProfile.Port, instanceProfile.Mode, instanceProfile.Public, instanceProfile.PasswordAuth, instanceProfile.Driver)
} }
func printGreetings() { func printGreetings() {

@ -3149,3 +3149,6 @@ definitions:
public: public:
type: boolean type: boolean
description: public is a flag that the instance is open for other users. description: public is a flag that the instance is open for other users.
passwordAuth:
type: boolean
description: password_auth is a flag whether the instance allows password authentication.

@ -41,17 +41,28 @@ require (
github.com/cenkalti/backoff/v4 v4.3.0 // indirect github.com/cenkalti/backoff/v4 v4.3.0 // indirect
github.com/desertbit/timer v0.0.0-20180107155436-c41aec40b27f // indirect github.com/desertbit/timer v0.0.0-20180107155436-c41aec40b27f // indirect
github.com/dustin/go-humanize v1.0.1 // indirect github.com/dustin/go-humanize v1.0.1 // indirect
github.com/fsnotify/fsnotify v1.7.0 // indirect
github.com/hashicorp/golang-lru/v2 v2.0.7 // indirect github.com/hashicorp/golang-lru/v2 v2.0.7 // indirect
github.com/hashicorp/hcl v1.0.0 // indirect
github.com/magiconair/properties v1.8.7 // indirect
github.com/mitchellh/mapstructure v1.5.0 // indirect
github.com/ncruces/go-strftime v0.1.9 // indirect github.com/ncruces/go-strftime v0.1.9 // indirect
github.com/pelletier/go-toml/v2 v2.2.2 // indirect
github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec // indirect github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec // indirect
github.com/rogpeppe/go-internal v1.11.0 // indirect github.com/rogpeppe/go-internal v1.11.0 // indirect
github.com/rs/cors v1.10.1 // indirect github.com/rs/cors v1.10.1 // indirect
github.com/sagikazarmark/locafero v0.4.0 // indirect github.com/sagikazarmark/locafero v0.4.0 // indirect
github.com/sagikazarmark/slog-shim v0.1.0 // indirect github.com/sagikazarmark/slog-shim v0.1.0 // indirect
github.com/sourcegraph/conc v0.3.0 // indirect github.com/sourcegraph/conc v0.3.0 // indirect
github.com/spf13/afero v1.11.0 // indirect
github.com/spf13/cast v1.6.0 // indirect
github.com/stoewer/go-strcase v1.3.0 // indirect github.com/stoewer/go-strcase v1.3.0 // indirect
github.com/subosito/gotenv v1.6.0 // indirect
go.uber.org/atomic v1.9.0 // indirect
go.uber.org/multierr v1.9.0 // indirect
golang.org/x/exp v0.0.0-20240409090435-93d18d7e34b8 // indirect golang.org/x/exp v0.0.0-20240409090435-93d18d7e34b8 // indirect
google.golang.org/genproto/googleapis/rpc v0.0.0-20240528184218-531527333157 // indirect google.golang.org/genproto/googleapis/rpc v0.0.0-20240528184218-531527333157 // indirect
gopkg.in/ini.v1 v1.67.0 // indirect
modernc.org/gc/v3 v3.0.0-20240304020402-f0dba7c97c2b // indirect modernc.org/gc/v3 v3.0.0-20240304020402-f0dba7c97c2b // indirect
modernc.org/libc v1.52.1 // indirect modernc.org/libc v1.52.1 // indirect
modernc.org/mathutil v1.6.0 // indirect modernc.org/mathutil v1.6.0 // indirect
@ -77,30 +88,20 @@ require (
github.com/aws/aws-sdk-go-v2/service/sts v1.30.3 // indirect github.com/aws/aws-sdk-go-v2/service/sts v1.30.3 // indirect
github.com/aws/smithy-go v1.20.3 // indirect github.com/aws/smithy-go v1.20.3 // indirect
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect
github.com/fsnotify/fsnotify v1.7.0 // indirect
github.com/golang-jwt/jwt v3.2.2+incompatible // indirect github.com/golang-jwt/jwt v3.2.2+incompatible // indirect
github.com/golang-jwt/jwt/v5 v5.2.1 github.com/golang-jwt/jwt/v5 v5.2.1
github.com/hashicorp/hcl v1.0.0 // indirect
github.com/inconshreveable/mousetrap v1.1.0 // indirect github.com/inconshreveable/mousetrap v1.1.0 // indirect
github.com/labstack/gommon v0.4.2 // indirect github.com/labstack/gommon v0.4.2 // indirect
github.com/magiconair/properties v1.8.7 // indirect
github.com/mattn/go-colorable v0.1.13 // indirect github.com/mattn/go-colorable v0.1.13 // indirect
github.com/mattn/go-isatty v0.0.20 // indirect github.com/mattn/go-isatty v0.0.20 // indirect
github.com/mitchellh/mapstructure v1.5.0 // indirect
github.com/pelletier/go-toml/v2 v2.2.2 // indirect
github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // indirect github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // indirect
github.com/soheilhy/cmux v0.1.5 github.com/soheilhy/cmux v0.1.5
github.com/spf13/afero v1.11.0 // indirect
github.com/spf13/cast v1.6.0 // indirect
github.com/spf13/pflag v1.0.5 // indirect github.com/spf13/pflag v1.0.5 // indirect
github.com/subosito/gotenv v1.6.0 // indirect
github.com/valyala/bytebufferpool v1.0.0 // indirect github.com/valyala/bytebufferpool v1.0.0 // indirect
github.com/valyala/fasttemplate v1.2.2 // indirect github.com/valyala/fasttemplate v1.2.2 // indirect
go.uber.org/multierr v1.11.0 // indirect
golang.org/x/sys v0.22.0 // indirect golang.org/x/sys v0.22.0 // indirect
golang.org/x/text v0.16.0 // indirect golang.org/x/text v0.16.0 // indirect
golang.org/x/time v0.5.0 // indirect golang.org/x/time v0.5.0 // indirect
google.golang.org/protobuf v1.34.2 google.golang.org/protobuf v1.34.2
gopkg.in/ini.v1 v1.67.0 // indirect
gopkg.in/yaml.v3 v3.0.1 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect
) )

@ -455,12 +455,14 @@ go.uber.org/atomic v1.3.2/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE=
go.uber.org/atomic v1.4.0/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE= go.uber.org/atomic v1.4.0/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE=
go.uber.org/atomic v1.5.0/go.mod h1:sABNBOSYdrvTF6hTgEIbc7YasKWGhgEQZyfxyTvoXHQ= go.uber.org/atomic v1.5.0/go.mod h1:sABNBOSYdrvTF6hTgEIbc7YasKWGhgEQZyfxyTvoXHQ=
go.uber.org/atomic v1.7.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc= go.uber.org/atomic v1.7.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc=
go.uber.org/atomic v1.9.0 h1:ECmE8Bn/WFTYwEW/bpKD3M8VtR/zQVbavAoalC1PYyE=
go.uber.org/atomic v1.9.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc=
go.uber.org/goleak v1.1.10/go.mod h1:8a7PlsEVH3e/a/GLqe5IIrQx6GzcnRmZEufDUTk4A7A= go.uber.org/goleak v1.1.10/go.mod h1:8a7PlsEVH3e/a/GLqe5IIrQx6GzcnRmZEufDUTk4A7A=
go.uber.org/multierr v1.1.0/go.mod h1:wR5kodmAFQ0UK8QlbwjlSNy0Z68gJhDJUG5sjR94q/0= go.uber.org/multierr v1.1.0/go.mod h1:wR5kodmAFQ0UK8QlbwjlSNy0Z68gJhDJUG5sjR94q/0=
go.uber.org/multierr v1.3.0/go.mod h1:VgVr7evmIr6uPjLBxg28wmKNXyqE9akIJ5XnfpiKl+4= go.uber.org/multierr v1.3.0/go.mod h1:VgVr7evmIr6uPjLBxg28wmKNXyqE9akIJ5XnfpiKl+4=
go.uber.org/multierr v1.6.0/go.mod h1:cdWPpRnG4AhwMwsgIHip0KRBQjJy5kYEpYjJxpXp9iU= go.uber.org/multierr v1.6.0/go.mod h1:cdWPpRnG4AhwMwsgIHip0KRBQjJy5kYEpYjJxpXp9iU=
go.uber.org/multierr v1.11.0 h1:blXXJkSxSSfBVBlC76pxqeO+LN3aDfLQo+309xJstO0= go.uber.org/multierr v1.9.0 h1:7fIwc/ZtS0q++VgcfqFDxSBZVv/Xo49/SYnDFupUwlI=
go.uber.org/multierr v1.11.0/go.mod h1:20+QtiLqy0Nd6FdQB9TLXag12DsQkrbs3htMFfDN80Y= go.uber.org/multierr v1.9.0/go.mod h1:X2jQV1h+kxSjClGpnseKVIxpmcjrj7MNnI0bnlfKTVQ=
go.uber.org/tools v0.0.0-20190618225709-2cfd321de3ee/go.mod h1:vJERXedbb3MVM5f9Ejo0C68/HhF8uaILCdgjnY+goOA= go.uber.org/tools v0.0.0-20190618225709-2cfd321de3ee/go.mod h1:vJERXedbb3MVM5f9Ejo0C68/HhF8uaILCdgjnY+goOA=
go.uber.org/zap v1.10.0/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q= go.uber.org/zap v1.10.0/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q=
go.uber.org/zap v1.13.0/go.mod h1:zwrFLgMcdUuIBviXEYEH1YKNaOBnKXsx2IPda5bBwHM= go.uber.org/zap v1.13.0/go.mod h1:zwrFLgMcdUuIBviXEYEH1YKNaOBnKXsx2IPda5bBwHM=

@ -23,6 +23,8 @@ message WorkspaceProfile {
string mode = 3; string mode = 3;
// public is a flag that the instance is open for other users. // public is a flag that the instance is open for other users.
bool public = 4; bool public = 4;
// password_auth is a flag whether the instance allows password authentication.
bool password_auth = 5;
} }
message GetWorkspaceProfileRequest {} message GetWorkspaceProfileRequest {}

@ -35,6 +35,8 @@ type WorkspaceProfile struct {
Mode string `protobuf:"bytes,3,opt,name=mode,proto3" json:"mode,omitempty"` Mode string `protobuf:"bytes,3,opt,name=mode,proto3" json:"mode,omitempty"`
// public is a flag that the instance is open for other users. // public is a flag that the instance is open for other users.
Public bool `protobuf:"varint,4,opt,name=public,proto3" json:"public,omitempty"` Public bool `protobuf:"varint,4,opt,name=public,proto3" json:"public,omitempty"`
// password_auth is a flag whether the instance allows password authentication.
PasswordAuth bool `protobuf:"varint,5,opt,name=password_auth,json=passwordAuth,proto3" json:"password_auth,omitempty"`
} }
func (x *WorkspaceProfile) Reset() { func (x *WorkspaceProfile) Reset() {
@ -97,6 +99,13 @@ func (x *WorkspaceProfile) GetPublic() bool {
return false return false
} }
func (x *WorkspaceProfile) GetPasswordAuth() bool {
if x != nil {
return x.PasswordAuth
}
return false
}
type GetWorkspaceProfileRequest struct { type GetWorkspaceProfileRequest struct {
state protoimpl.MessageState state protoimpl.MessageState
sizeCache protoimpl.SizeCache sizeCache protoimpl.SizeCache
@ -142,37 +151,40 @@ var file_api_v1_workspace_service_proto_rawDesc = []byte{
0x63, 0x65, 0x5f, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x65, 0x5f, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f,
0x12, 0x0c, 0x6d, 0x65, 0x6d, 0x6f, 0x73, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x76, 0x31, 0x1a, 0x1c, 0x12, 0x0c, 0x6d, 0x65, 0x6d, 0x6f, 0x73, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x76, 0x31, 0x1a, 0x1c,
0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2f, 0x61, 0x70, 0x69, 0x2f, 0x61, 0x6e, 0x6e, 0x6f, 0x74, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2f, 0x61, 0x70, 0x69, 0x2f, 0x61, 0x6e, 0x6e, 0x6f, 0x74,
0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x22, 0x6e, 0x0a, 0x10, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x22, 0x93, 0x01, 0x0a,
0x10, 0x57, 0x6f, 0x72, 0x6b, 0x73, 0x70, 0x61, 0x63, 0x65, 0x50, 0x72, 0x6f, 0x66, 0x69, 0x6c,
0x65, 0x12, 0x14, 0x0a, 0x05, 0x6f, 0x77, 0x6e, 0x65, 0x72, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09,
0x52, 0x05, 0x6f, 0x77, 0x6e, 0x65, 0x72, 0x12, 0x18, 0x0a, 0x07, 0x76, 0x65, 0x72, 0x73, 0x69,
0x6f, 0x6e, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f,
0x6e, 0x12, 0x12, 0x0a, 0x04, 0x6d, 0x6f, 0x64, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52,
0x04, 0x6d, 0x6f, 0x64, 0x65, 0x12, 0x16, 0x0a, 0x06, 0x70, 0x75, 0x62, 0x6c, 0x69, 0x63, 0x18,
0x04, 0x20, 0x01, 0x28, 0x08, 0x52, 0x06, 0x70, 0x75, 0x62, 0x6c, 0x69, 0x63, 0x12, 0x23, 0x0a,
0x0d, 0x70, 0x61, 0x73, 0x73, 0x77, 0x6f, 0x72, 0x64, 0x5f, 0x61, 0x75, 0x74, 0x68, 0x18, 0x05,
0x20, 0x01, 0x28, 0x08, 0x52, 0x0c, 0x70, 0x61, 0x73, 0x73, 0x77, 0x6f, 0x72, 0x64, 0x41, 0x75,
0x74, 0x68, 0x22, 0x1c, 0x0a, 0x1a, 0x47, 0x65, 0x74, 0x57, 0x6f, 0x72, 0x6b, 0x73, 0x70, 0x61,
0x63, 0x65, 0x50, 0x72, 0x6f, 0x66, 0x69, 0x6c, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74,
0x32, 0x97, 0x01, 0x0a, 0x10, 0x57, 0x6f, 0x72, 0x6b, 0x73, 0x70, 0x61, 0x63, 0x65, 0x53, 0x65,
0x72, 0x76, 0x69, 0x63, 0x65, 0x12, 0x82, 0x01, 0x0a, 0x13, 0x47, 0x65, 0x74, 0x57, 0x6f, 0x72,
0x6b, 0x73, 0x70, 0x61, 0x63, 0x65, 0x50, 0x72, 0x6f, 0x66, 0x69, 0x6c, 0x65, 0x12, 0x28, 0x2e,
0x6d, 0x65, 0x6d, 0x6f, 0x73, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x76, 0x31, 0x2e, 0x47, 0x65, 0x74,
0x57, 0x6f, 0x72, 0x6b, 0x73, 0x70, 0x61, 0x63, 0x65, 0x50, 0x72, 0x6f, 0x66, 0x69, 0x6c, 0x65, 0x57, 0x6f, 0x72, 0x6b, 0x73, 0x70, 0x61, 0x63, 0x65, 0x50, 0x72, 0x6f, 0x66, 0x69, 0x6c, 0x65,
0x12, 0x14, 0x0a, 0x05, 0x6f, 0x77, 0x6e, 0x65, 0x72, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1e, 0x2e, 0x6d, 0x65, 0x6d, 0x6f, 0x73, 0x2e,
0x05, 0x6f, 0x77, 0x6e, 0x65, 0x72, 0x12, 0x18, 0x0a, 0x07, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x61, 0x70, 0x69, 0x2e, 0x76, 0x31, 0x2e, 0x57, 0x6f, 0x72, 0x6b, 0x73, 0x70, 0x61, 0x63, 0x65,
0x6e, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x50, 0x72, 0x6f, 0x66, 0x69, 0x6c, 0x65, 0x22, 0x21, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x1b, 0x12,
0x12, 0x12, 0x0a, 0x04, 0x6d, 0x6f, 0x64, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x19, 0x2f, 0x61, 0x70, 0x69, 0x2f, 0x76, 0x31, 0x2f, 0x77, 0x6f, 0x72, 0x6b, 0x73, 0x70, 0x61,
0x6d, 0x6f, 0x64, 0x65, 0x12, 0x16, 0x0a, 0x06, 0x70, 0x75, 0x62, 0x6c, 0x69, 0x63, 0x18, 0x04, 0x63, 0x65, 0x2f, 0x70, 0x72, 0x6f, 0x66, 0x69, 0x6c, 0x65, 0x42, 0xad, 0x01, 0x0a, 0x10, 0x63,
0x20, 0x01, 0x28, 0x08, 0x52, 0x06, 0x70, 0x75, 0x62, 0x6c, 0x69, 0x63, 0x22, 0x1c, 0x0a, 0x1a, 0x6f, 0x6d, 0x2e, 0x6d, 0x65, 0x6d, 0x6f, 0x73, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x76, 0x31, 0x42,
0x47, 0x65, 0x74, 0x57, 0x6f, 0x72, 0x6b, 0x73, 0x70, 0x61, 0x63, 0x65, 0x50, 0x72, 0x6f, 0x66, 0x15, 0x57, 0x6f, 0x72, 0x6b, 0x73, 0x70, 0x61, 0x63, 0x65, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63,
0x69, 0x6c, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x32, 0x97, 0x01, 0x0a, 0x10, 0x57, 0x65, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x50, 0x01, 0x5a, 0x30, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62,
0x6f, 0x72, 0x6b, 0x73, 0x70, 0x61, 0x63, 0x65, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x12, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x75, 0x73, 0x65, 0x6d, 0x65, 0x6d, 0x6f, 0x73, 0x2f, 0x6d, 0x65,
0x82, 0x01, 0x0a, 0x13, 0x47, 0x65, 0x74, 0x57, 0x6f, 0x72, 0x6b, 0x73, 0x70, 0x61, 0x63, 0x65, 0x6d, 0x6f, 0x73, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2f, 0x67, 0x65, 0x6e, 0x2f, 0x61, 0x70,
0x50, 0x72, 0x6f, 0x66, 0x69, 0x6c, 0x65, 0x12, 0x28, 0x2e, 0x6d, 0x65, 0x6d, 0x6f, 0x73, 0x2e, 0x69, 0x2f, 0x76, 0x31, 0x3b, 0x61, 0x70, 0x69, 0x76, 0x31, 0xa2, 0x02, 0x03, 0x4d, 0x41, 0x58,
0x61, 0x70, 0x69, 0x2e, 0x76, 0x31, 0x2e, 0x47, 0x65, 0x74, 0x57, 0x6f, 0x72, 0x6b, 0x73, 0x70, 0xaa, 0x02, 0x0c, 0x4d, 0x65, 0x6d, 0x6f, 0x73, 0x2e, 0x41, 0x70, 0x69, 0x2e, 0x56, 0x31, 0xca,
0x61, 0x63, 0x65, 0x50, 0x72, 0x6f, 0x66, 0x69, 0x6c, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x02, 0x0c, 0x4d, 0x65, 0x6d, 0x6f, 0x73, 0x5c, 0x41, 0x70, 0x69, 0x5c, 0x56, 0x31, 0xe2, 0x02,
0x74, 0x1a, 0x1e, 0x2e, 0x6d, 0x65, 0x6d, 0x6f, 0x73, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x76, 0x31, 0x18, 0x4d, 0x65, 0x6d, 0x6f, 0x73, 0x5c, 0x41, 0x70, 0x69, 0x5c, 0x56, 0x31, 0x5c, 0x47, 0x50,
0x2e, 0x57, 0x6f, 0x72, 0x6b, 0x73, 0x70, 0x61, 0x63, 0x65, 0x50, 0x72, 0x6f, 0x66, 0x69, 0x6c, 0x42, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0xea, 0x02, 0x0e, 0x4d, 0x65, 0x6d, 0x6f,
0x65, 0x22, 0x21, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x1b, 0x12, 0x19, 0x2f, 0x61, 0x70, 0x69, 0x2f, 0x73, 0x3a, 0x3a, 0x41, 0x70, 0x69, 0x3a, 0x3a, 0x56, 0x31, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74,
0x76, 0x31, 0x2f, 0x77, 0x6f, 0x72, 0x6b, 0x73, 0x70, 0x61, 0x63, 0x65, 0x2f, 0x70, 0x72, 0x6f, 0x6f, 0x33,
0x66, 0x69, 0x6c, 0x65, 0x42, 0xad, 0x01, 0x0a, 0x10, 0x63, 0x6f, 0x6d, 0x2e, 0x6d, 0x65, 0x6d,
0x6f, 0x73, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x76, 0x31, 0x42, 0x15, 0x57, 0x6f, 0x72, 0x6b, 0x73,
0x70, 0x61, 0x63, 0x65, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x50, 0x72, 0x6f, 0x74, 0x6f,
0x50, 0x01, 0x5a, 0x30, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x75,
0x73, 0x65, 0x6d, 0x65, 0x6d, 0x6f, 0x73, 0x2f, 0x6d, 0x65, 0x6d, 0x6f, 0x73, 0x2f, 0x70, 0x72,
0x6f, 0x74, 0x6f, 0x2f, 0x67, 0x65, 0x6e, 0x2f, 0x61, 0x70, 0x69, 0x2f, 0x76, 0x31, 0x3b, 0x61,
0x70, 0x69, 0x76, 0x31, 0xa2, 0x02, 0x03, 0x4d, 0x41, 0x58, 0xaa, 0x02, 0x0c, 0x4d, 0x65, 0x6d,
0x6f, 0x73, 0x2e, 0x41, 0x70, 0x69, 0x2e, 0x56, 0x31, 0xca, 0x02, 0x0c, 0x4d, 0x65, 0x6d, 0x6f,
0x73, 0x5c, 0x41, 0x70, 0x69, 0x5c, 0x56, 0x31, 0xe2, 0x02, 0x18, 0x4d, 0x65, 0x6d, 0x6f, 0x73,
0x5c, 0x41, 0x70, 0x69, 0x5c, 0x56, 0x31, 0x5c, 0x47, 0x50, 0x42, 0x4d, 0x65, 0x74, 0x61, 0x64,
0x61, 0x74, 0x61, 0xea, 0x02, 0x0e, 0x4d, 0x65, 0x6d, 0x6f, 0x73, 0x3a, 0x3a, 0x41, 0x70, 0x69,
0x3a, 0x3a, 0x56, 0x31, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,
} }
var ( var (

@ -8,30 +8,29 @@ import (
"strings" "strings"
"github.com/pkg/errors" "github.com/pkg/errors"
"github.com/spf13/viper"
"github.com/usememos/memos/server/version"
) )
// Profile is the configuration to start main server. // Profile is the configuration to start main server.
type Profile struct { type Profile struct {
// Mode can be "prod" or "dev" or "demo" // Mode can be "prod" or "dev" or "demo"
Mode string `json:"mode"` Mode string
// Addr is the binding address for server // Addr is the binding address for server
Addr string `json:"-"` Addr string
// Port is the binding port for server // Port is the binding port for server
Port int `json:"-"` Port int
// Data is the data directory // Data is the data directory
Data string `json:"-"` Data string
// DSN points to where memos stores its own data // DSN points to where memos stores its own data
DSN string `json:"-"` DSN string
// Driver is the database driver // Driver is the database driver
// sqlite, mysql // sqlite, mysql
Driver string `json:"-"` Driver string
// Version is the current version of server // Version is the current version of server
Version string `json:"version"` Version string
// Pubic is the flag whether the instance is public for others. // Pubic is the flag whether the instance is public for others.
Public bool `json:"public"` Public bool
// PasswordAuth is the flag whether the instance uses password authentication.
PasswordAuth bool
} }
func (p *Profile) IsDev() bool { func (p *Profile) IsDev() bool {
@ -57,45 +56,36 @@ func checkDataDir(dataDir string) (string, error) {
return dataDir, nil return dataDir, nil
} }
// GetProfile will return a profile for dev or prod. func (p *Profile) Validate() error {
func GetProfile() (*Profile, error) { if p.Mode != "demo" && p.Mode != "dev" && p.Mode != "prod" {
profile := Profile{} p.Mode = "demo"
err := viper.Unmarshal(&profile)
if err != nil {
return nil, err
} }
if profile.Mode != "demo" && profile.Mode != "dev" && profile.Mode != "prod" { if p.Mode == "prod" && p.Data == "" {
profile.Mode = "demo"
}
if profile.Mode == "prod" && profile.Data == "" {
if runtime.GOOS == "windows" { if runtime.GOOS == "windows" {
profile.Data = filepath.Join(os.Getenv("ProgramData"), "memos") p.Data = filepath.Join(os.Getenv("ProgramData"), "memos")
if _, err := os.Stat(p.Data); os.IsNotExist(err) {
if _, err := os.Stat(profile.Data); os.IsNotExist(err) { if err := os.MkdirAll(p.Data, 0770); err != nil {
if err := os.MkdirAll(profile.Data, 0770); err != nil { fmt.Printf("Failed to create data directory: %s, err: %+v\n", p.Data, err)
fmt.Printf("Failed to create data directory: %s, err: %+v\n", profile.Data, err) return err
return nil, err
} }
} }
} else { } else {
profile.Data = "/var/opt/memos" p.Data = "/var/opt/memos"
} }
} }
dataDir, err := checkDataDir(profile.Data) dataDir, err := checkDataDir(p.Data)
if err != nil { if err != nil {
fmt.Printf("Failed to check dsn: %s, err: %+v\n", dataDir, err) fmt.Printf("Failed to check dsn: %s, err: %+v\n", dataDir, err)
return nil, err return err
} }
profile.Data = dataDir p.Data = dataDir
if profile.Driver == "sqlite" && profile.DSN == "" { if p.Driver == "sqlite" && p.DSN == "" {
dbFile := fmt.Sprintf("memos_%s.db", profile.Mode) dbFile := fmt.Sprintf("memos_%s.db", p.Mode)
profile.DSN = filepath.Join(dataDir, dbFile) p.DSN = filepath.Join(dataDir, dbFile)
} }
profile.Version = version.GetCurrentVersion(profile.Mode)
return &profile, nil return nil
} }

@ -224,7 +224,7 @@ func (s *APIV1Service) SignOut(ctx context.Context, _ *v1pb.SignOutRequest) (*em
Name: fmt.Sprintf("%s%d", UserNamePrefix, user.ID), Name: fmt.Sprintf("%s%d", UserNamePrefix, user.ID),
AccessToken: accessToken, AccessToken: accessToken,
}); err != nil { }); err != nil {
slog.Error("failed to delete access token", slog.Any("err", err)) slog.Error("failed to delete access token", "error", err)
} }
} }
} }

@ -13,9 +13,10 @@ import (
func (s *APIV1Service) GetWorkspaceProfile(ctx context.Context, _ *v1pb.GetWorkspaceProfileRequest) (*v1pb.WorkspaceProfile, error) { func (s *APIV1Service) GetWorkspaceProfile(ctx context.Context, _ *v1pb.GetWorkspaceProfileRequest) (*v1pb.WorkspaceProfile, error) {
workspaceProfile := &v1pb.WorkspaceProfile{ workspaceProfile := &v1pb.WorkspaceProfile{
Version: s.Profile.Version, Version: s.Profile.Version,
Mode: s.Profile.Mode, Mode: s.Profile.Mode,
Public: s.Profile.Public, Public: s.Profile.Public,
PasswordAuth: s.Profile.PasswordAuth,
} }
owner, err := s.GetInstanceOwner(ctx) owner, err := s.GetInstanceOwner(ctx)
if err != nil { if err != nil {
@ -24,8 +25,9 @@ func (s *APIV1Service) GetWorkspaceProfile(ctx context.Context, _ *v1pb.GetWorks
if owner != nil { if owner != nil {
workspaceProfile.Owner = owner.Name workspaceProfile.Owner = owner.Name
} else { } else {
// If owner is not found, set public to true. // If owner is not found, set Public/PasswordAuth to true.
workspaceProfile.Public = true workspaceProfile.Public = true
workspaceProfile.PasswordAuth = true
} }
return workspaceProfile, nil return workspaceProfile, nil
} }

@ -102,19 +102,19 @@ func (s *Server) Start(ctx context.Context) error {
go func() { go func() {
grpcListener := muxServer.MatchWithWriters(cmux.HTTP2MatchHeaderFieldSendSettings("content-type", "application/grpc")) grpcListener := muxServer.MatchWithWriters(cmux.HTTP2MatchHeaderFieldSendSettings("content-type", "application/grpc"))
if err := s.grpcServer.Serve(grpcListener); err != nil { if err := s.grpcServer.Serve(grpcListener); err != nil {
slog.Error("failed to serve gRPC", err) slog.Error("failed to serve gRPC", "error", err)
} }
}() }()
go func() { go func() {
httpListener := muxServer.Match(cmux.HTTP1Fast(http.MethodPatch)) httpListener := muxServer.Match(cmux.HTTP1Fast(http.MethodPatch))
s.echoServer.Listener = httpListener s.echoServer.Listener = httpListener
if err := s.echoServer.Start(address); err != nil { if err := s.echoServer.Start(address); err != nil {
slog.Error("failed to start echo server", err) slog.Error("failed to start echo server", "error", err)
} }
}() }()
go func() { go func() {
if err := muxServer.Serve(); err != nil { if err := muxServer.Serve(); err != nil {
slog.Error("mux server listen error", err) slog.Error("mux server listen error", "error", err)
} }
}() }()
s.StartBackgroundRunners(ctx) s.StartBackgroundRunners(ctx)

@ -63,7 +63,7 @@ func (p *S3ObjectPresigner) CheckAndPresign(ctx context.Context) {
s3Client, err := s3.NewClient(ctx, s3Config) s3Client, err := s3.NewClient(ctx, s3Config)
if err != nil { if err != nil {
slog.Error("Failed to create S3 client", slog.Any("err", err)) slog.Error("Failed to create S3 client", "error", err)
continue continue
} }

@ -52,7 +52,7 @@ func (d *DB) GetCurrentDBSize(ctx context.Context) (int64, error) {
" GROUP BY `table_schema`" " GROUP BY `table_schema`"
rows, err := d.db.QueryContext(ctx, query, d.config.DBName) rows, err := d.db.QueryContext(ctx, query, d.config.DBName)
if err != nil { if err != nil {
slog.Error("Query db size error, make sure you have enough privilege", err) slog.Error("Query db size error, make sure you have enough privilege", "error", err)
return 0, err return 0, err
} }
defer rows.Close() defer rows.Close()

@ -116,57 +116,61 @@ const SignIn = () => {
{workspaceGeneralSetting.customProfile?.title || "Memos"} {workspaceGeneralSetting.customProfile?.title || "Memos"}
</p> </p>
</div> </div>
<form className="w-full mt-2" onSubmit={handleFormSubmit}> {commonContext.profile.passwordAuth ? (
<div className="flex flex-col justify-start items-start w-full gap-4"> <form className="w-full mt-2" onSubmit={handleFormSubmit}>
<div className="w-full flex flex-col justify-start items-start"> <div className="flex flex-col justify-start items-start w-full gap-4">
<span className="leading-8 text-gray-600">{t("common.username")}</span> <div className="w-full flex flex-col justify-start items-start">
<Input <span className="leading-8 text-gray-600">{t("common.username")}</span>
className="w-full" <Input
size="lg" className="w-full"
type="text" size="lg"
readOnly={actionBtnLoadingState.isLoading} type="text"
placeholder={t("common.username")} readOnly={actionBtnLoadingState.isLoading}
value={username} placeholder={t("common.username")}
onChange={handleUsernameInputChanged} value={username}
required onChange={handleUsernameInputChanged}
required
/>
</div>
<div className="w-full flex flex-col justify-start items-start">
<span className="leading-8 text-gray-600">{t("common.password")}</span>
<Input
className="w-full"
size="lg"
type="password"
readOnly={actionBtnLoadingState.isLoading}
placeholder={t("common.password")}
value={password}
onChange={handlePasswordInputChanged}
required
/>
</div>
</div>
<div className="flex flex-row justify-start items-center w-full mt-6">
<Checkbox
className="dark:!text-gray-400"
label={t("common.remember-me")}
checked={remember}
onChange={(e) => setRemember(e.target.checked)}
/> />
</div> </div>
<div className="w-full flex flex-col justify-start items-start"> <div className="flex flex-row justify-end items-center w-full mt-6">
<span className="leading-8 text-gray-600">{t("common.password")}</span> <Button
<Input
className="w-full" className="w-full"
size="lg" size="md"
type="password" type="submit"
readOnly={actionBtnLoadingState.isLoading} disabled={actionBtnLoadingState.isLoading}
placeholder={t("common.password")} loading={actionBtnLoadingState.isLoading}
value={password} onClick={handleSignInButtonClick}
onChange={handlePasswordInputChanged} >
required {t("common.sign-in")}
/> </Button>
</div> </div>
</div> </form>
<div className="flex flex-row justify-start items-center w-full mt-6"> ) : (
<Checkbox <p className="w-full text-2xl mt-2 dark:text-gray-500">Password auth is not allowed.</p>
className="dark:!text-gray-400" )}
label={t("common.remember-me")} {commonContext.profile.public && commonContext.profile.passwordAuth && (
checked={remember}
onChange={(e) => setRemember(e.target.checked)}
/>
</div>
<div className="flex flex-row justify-end items-center w-full mt-6">
<Button
className="w-full"
size="md"
type="submit"
disabled={actionBtnLoadingState.isLoading}
loading={actionBtnLoadingState.isLoading}
onClick={handleSignInButtonClick}
>
{t("common.sign-in")}
</Button>
</div>
</form>
{commonContext.profile.public && (
<p className="w-full mt-4 text-sm"> <p className="w-full mt-4 text-sm">
<span className="dark:text-gray-500">{t("auth.sign-up-tip")}</span> <span className="dark:text-gray-500">{t("auth.sign-up-tip")}</span>
<Link to="/auth/signup" className="cursor-pointer ml-2 text-blue-600 hover:underline" unstable_viewTransition> <Link to="/auth/signup" className="cursor-pointer ml-2 text-blue-600 hover:underline" unstable_viewTransition>

@ -1,6 +1,6 @@
import { Button, Input } from "@mui/joy"; import { Button, Input } from "@mui/joy";
import { ClientError } from "nice-grpc-web"; import { ClientError } from "nice-grpc-web";
import { useEffect, useState } from "react"; import { useState } from "react";
import { toast } from "react-hot-toast"; import { toast } from "react-hot-toast";
import { Link } from "react-router-dom"; import { Link } from "react-router-dom";
import AppearanceSelect from "@/components/AppearanceSelect"; import AppearanceSelect from "@/components/AppearanceSelect";
@ -26,12 +26,6 @@ const SignUp = () => {
const workspaceGeneralSetting = const workspaceGeneralSetting =
workspaceSettingStore.getWorkspaceSettingByKey(WorkspaceSettingKey.GENERAL).generalSetting || WorkspaceGeneralSetting.fromPartial({}); workspaceSettingStore.getWorkspaceSettingByKey(WorkspaceSettingKey.GENERAL).generalSetting || WorkspaceGeneralSetting.fromPartial({});
useEffect(() => {
if (!commonContext.profile.public) {
toast.error("Sign up is not allowed.");
}
}, []);
const handleUsernameInputChanged = (e: React.ChangeEvent<HTMLInputElement>) => { const handleUsernameInputChanged = (e: React.ChangeEvent<HTMLInputElement>) => {
const text = e.target.value as string; const text = e.target.value as string;
setUsername(text); setUsername(text);
@ -85,49 +79,55 @@ const SignUp = () => {
{workspaceGeneralSetting.customProfile?.title || "Memos"} {workspaceGeneralSetting.customProfile?.title || "Memos"}
</p> </p>
</div> </div>
<p className="w-full text-2xl mt-2 dark:text-gray-500">{t("auth.create-your-account")}</p> {commonContext.profile.public ? (
<form className="w-full mt-2" onSubmit={handleFormSubmit}> <>
<div className="flex flex-col justify-start items-start w-full gap-4"> <p className="w-full text-2xl mt-2 dark:text-gray-500">{t("auth.create-your-account")}</p>
<div className="w-full flex flex-col justify-start items-start"> <form className="w-full mt-2" onSubmit={handleFormSubmit}>
<span className="leading-8 text-gray-600">{t("common.username")}</span> <div className="flex flex-col justify-start items-start w-full gap-4">
<Input <div className="w-full flex flex-col justify-start items-start">
className="w-full" <span className="leading-8 text-gray-600">{t("common.username")}</span>
size="lg" <Input
type="text" className="w-full"
readOnly={actionBtnLoadingState.isLoading} size="lg"
placeholder={t("common.username")} type="text"
value={username} readOnly={actionBtnLoadingState.isLoading}
onChange={handleUsernameInputChanged} placeholder={t("common.username")}
required value={username}
/> onChange={handleUsernameInputChanged}
</div> required
<div className="w-full flex flex-col justify-start items-start"> />
<span className="leading-8 text-gray-600">{t("common.password")}</span> </div>
<Input <div className="w-full flex flex-col justify-start items-start">
className="w-full" <span className="leading-8 text-gray-600">{t("common.password")}</span>
size="lg" <Input
type="password" className="w-full"
readOnly={actionBtnLoadingState.isLoading} size="lg"
placeholder={t("common.password")} type="password"
value={password} readOnly={actionBtnLoadingState.isLoading}
onChange={handlePasswordInputChanged} placeholder={t("common.password")}
required value={password}
/> onChange={handlePasswordInputChanged}
</div> required
</div> />
<div className="flex flex-row justify-end items-center w-full mt-6"> </div>
<Button </div>
className="w-full" <div className="flex flex-row justify-end items-center w-full mt-6">
size="md" <Button
type="submit" className="w-full"
disabled={actionBtnLoadingState.isLoading} size="md"
loading={actionBtnLoadingState.isLoading} type="submit"
onClick={handleSignUpButtonClick} disabled={actionBtnLoadingState.isLoading}
> loading={actionBtnLoadingState.isLoading}
{t("common.sign-up")} onClick={handleSignUpButtonClick}
</Button> >
</div> {t("common.sign-up")}
</form> </Button>
</div>
</form>
</>
) : (
<p className="w-full text-2xl mt-2 dark:text-gray-500">Sign up is not allowed.</p>
)}
{!commonContext.profile.owner ? ( {!commonContext.profile.owner ? (
<p className="w-full mt-4 text-sm font-medium dark:text-gray-500">{t("auth.host-tip")}</p> <p className="w-full mt-4 text-sm font-medium dark:text-gray-500">{t("auth.host-tip")}</p>
) : ( ) : (

Loading…
Cancel
Save