package client import ( "encoding/json" "errors" "os" "sync" "github.com/awnumar/memguard" ) type Config struct { // UserConfig SavePassword bool `json:"save_password,omitempty"` SavedPassword string `json:"saved_password,omitempty"` PasswordTip string `json:"password_tip,omitempty"` PasswordTipUnlock string `json:"password_tip_unlock,omitempty"` // Technical IdentityFile string `json:"identity_file,omitempty"` StoragePath string `json:"storage_path,omitempty"` MaxIdsPerUser int `json:"max_ids_per_user,omitempty"` MsgDbRollingPeriod int `json:"msg_db_rolling_period,omitempty"` Chunksize int64 `json:"chunksize,omitempty"` DbSize int `json:"db_size,omitempty"` UserAgent string `json:"user_agent,omitempty"` // Network ServerPollInterval int `json:"server_poll_interval,omitempty"` HttpTimeOut int `json:"http_timeout,omitempty"` HttpLongPoll int `json:"http_long_poll,omitempty"` // GUI LastOpenChat string `json:"last_open_chat,omitempty"` SoundNotificationEnable bool `json:"sound_notification_enable,omitempty"` DefaultNotificationSound string `json:"default_notification_sound,omitempty"` NotificationVibeEnable bool `json:"notification_vibe_enable,omitempty"` DefaultNotificationVibe string `json:"default_notification_vibe,omitempty"` NotificationLEDEnable bool `json:"notification_led_enable,omitempty"` DefaultNotificationLEDColor string `json:"default_notification_led_color,omitempty"` VisualNotificationEnable bool `json:"visual_notification_enable,omitempty"` VisualNotificationModes string `json:"visual_notifiaction_modes,omitempty"` PrivateChatNotificationsEnable bool `json:"private_chat_notifiactions_enable,omitempty"` GroupChatNotificationsEnable bool `json:"group_chat_notifiactions_enable,omitempty"` ChannelNotificationsEnable bool `json:"channel_notifications_enable,omitempty"` Language string `json:"language,omitempty"` Theme string `json:"theme,omitempty"` FingerprintEnable bool `json:"fingerprint_enable,omitempty"` ShowFavoriteContacts bool `json:"show_favorite_contacts,omitempty"` NightModeEnable bool `json:"night_mode_enable,omitempty"` // Debug DbSuffix string `json:"db_suffix,omitempty"` // Inner memoryPassword *memguard.LockedBuffer additionalPasswords []*memguard.LockedBuffer me *Identity } var instance *Config var once sync.Once func GetConfig() *Config { once.Do(func() { instance = &Config{} }) return instance } func (c *Config) Load(filename string) error { data, err := os.ReadFile(filename) if err != nil { return err } err = json.Unmarshal(data, c) if err != nil { return err } // override values if not set or wrong if c.HttpTimeOut <= 0 { c.HttpTimeOut = 10 c.Save(filename) } if c.HttpLongPoll <= 1 { c.HttpLongPoll = 300 c.Save(filename) } return nil } func (c *Config) Save(filename string) error { data, err := json.Marshal(c) if err != nil { return err } err = os.WriteFile(filename, data, 0600) if err != nil { return err } return nil } func (c *Config) SetMemPass(pass string) error { if c.memoryPassword != nil { c.memoryPassword.Destroy() } c.memoryPassword = memguard.NewBufferFromBytes([]byte(pass)) return nil } func (c *Config) GetMemPass() (string, error) { if c.memoryPassword == nil { return "", errors.New("password not set") } return string(c.memoryPassword.Bytes()), nil } func (c *Config) GetIdentity() *Identity { return c.me } func (c *Config) SetIdentity(id *Identity) { c.me = id } func (c *Config) SaveIdentity() error { return c.me.Save() } func (c *Config) Clean() { if c.memoryPassword != nil { c.memoryPassword.Destroy() c.memoryPassword = nil } for _, buf := range c.additionalPasswords { if buf != nil { buf.Destroy() } } c.additionalPasswords = []*memguard.LockedBuffer{} } // AddAdditionalPassword securely stores an additional password in protected memory func (c *Config) AddAdditionalPassword(password string) { buf := memguard.NewBufferFromBytes([]byte(password)) c.additionalPasswords = append(c.additionalPasswords, buf) } // GetAdditionalPasswords returns all additional passwords as strings func (c *Config) GetAdditionalPasswords() ([]string, error) { passwords := make([]string, 0, len(c.additionalPasswords)) for _, buf := range c.additionalPasswords { if buf == nil { continue } passwords = append(passwords, string(buf.Bytes())) } return passwords, nil } // GetAdditionalPasswordAt returns the password at the specified index func (c *Config) GetAdditionalPasswordAt(index int) (string, error) { if index < 0 || index >= len(c.additionalPasswords) { return "", errors.New("index out of range") } if c.additionalPasswords[index] == nil { return "", errors.New("password at index is nil") } return string(c.additionalPasswords[index].Bytes()), nil } // RemoveAdditionalPasswordAt removes and destroys the password at the specified index func (c *Config) RemoveAdditionalPasswordAt(index int) error { if index < 0 || index >= len(c.additionalPasswords) { return errors.New("index out of range") } if c.additionalPasswords[index] != nil { c.additionalPasswords[index].Destroy() } c.additionalPasswords = append(c.additionalPasswords[:index], c.additionalPasswords[index+1:]...) return nil } // ClearAdditionalPasswords removes and destroys all additional passwords func (c *Config) ClearAdditionalPasswords() { for _, buf := range c.additionalPasswords { if buf != nil { buf.Destroy() } } c.additionalPasswords = []*memguard.LockedBuffer{} }