207 lines
6.0 KiB
Go
207 lines
6.0 KiB
Go
package client
|
|
|
|
import (
|
|
"encoding/json"
|
|
"errors"
|
|
"fmt"
|
|
"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) Validate() error {
|
|
if c.StoragePath == "" {
|
|
return errors.New("storage_path is required")
|
|
}
|
|
|
|
if c.Chunksize < 1024 || c.Chunksize > 10*1024*1024 {
|
|
return fmt.Errorf("chunksize must be between 1KB and 10MB, got %d", c.Chunksize)
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
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
|
|
}
|
|
if err := c.Validate(); err != nil {
|
|
return fmt.Errorf("invalid config: %w", 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{}
|
|
}
|