db

package
v0.0.0-...-386d234 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Jun 7, 2020 License: MIT Imports: 21 Imported by: 0

Documentation

Overview

一个带有加密功能的简陋数据库.

Index

Constants

View Source
const (
	KeySize   = 32
	NonceSize = 24

	DateTimeFormat = "2006-01-02 15:04:05"

	// 数据库碎片文件的后缀名
	FragExt = ".db.frag"

	// 数据库备份文件的后缀名
	TarballExt = ".tar.gz"
)

Variables

View Source
var (
	FileNotFound = errors.New("找不到数据库文件")
)

Functions

func DeleteFiles

func DeleteFiles(filePaths []string) error

func NewID

func NewID() string

NewID 返回一个由时间戳和随机数组成的 id, 经测试瞬间生成一万个 id 不会重复. 由于时间戳的精度为秒, 因此如果两次生成 id 之间超过一秒, 则绝对不会重复.

Types

type DB

type DB struct {
	// 每次使用 DB 时注意需要上锁.
	sync.RWMutex

	// 本数据库具有定时关闭功能, 这是数据库启动时刻和有效时长.
	StartedAt time.Time
	ValidTerm time.Duration

	// 数据库文件的绝对路径, 备份文件夹的绝对路径.
	// 另外, 数据库碎片文件的后缀名和数据库备份文件的后缀名在 db/init.go 中定义.
	// 为了方便测试, 权限设为 public.
	FullPath  string
	BackupDir string
	// contains filtered or unexported fields
}

DB 相当于一个数据库. 其中 mimaTable 相当于一个数据表, Mima 相当于这个数据表的 schema.

func NewDB

func NewDB(fullPath, backupDir string) *DB

NewDB 生成一个新的 DB. 此时, 内存数据库里没有数据, 也没有 key. 要么通过 DB.Init 生成新的数据库, 要么通过 DB.Rebuild 从文件中恢复数据库.

func (*DB) Add

func (db *DB) Add(mima *Mima) error

Add 新增一个 mima 到数据库中, 并生成一块数据库碎片. 此时不检查 Alias 冲突, 因为此时不新增 Alias. 只能在 Edit 时增加新的 Alias. 此时不重新排序, 新 mima 直接加到最后, 因为新记录的更新日期必然是最新的.

func (*DB) All

func (db *DB) All() (all []*MimaForm)

All 返回全部 Mima, 但不包含 index:0, 也不包含已软删除的条目. 并且删除含密码和备注等敏感信息. 另外, 更新时间最新(最近)的排在前面.

func (*DB) ChangeUserKey

func (db *DB) ChangeUserKey(newPassword string) error

ChangeUserKey 根据新密码更改 db.userKey, 重写 db.FullPath.

func (*DB) DeleteForeverByID

func (db *DB) DeleteForeverByID(id string) error

DeleteForeverByID 彻底删除一条记录, 并生成一块数据库碎片.

func (*DB) DeleteHistoryItem

func (db *DB) DeleteHistoryItem(id string, datetime string) error

func (*DB) DeletedMimas

func (db *DB) DeletedMimas() (deleted []*MimaForm)

DeletedMimas 返回全部被软删除的 Mima, 不包含密码. 删除日期最新(最近)的排在前面.

func (*DB) EqualByUpdatedAt

func (db *DB) EqualByUpdatedAt(data io.ReadCloser) error

EqualByUpdatedAt 用于对比从云端下载回来的数据是否与内存数据库一致.

func (*DB) EqualToUserKey

func (db *DB) EqualToUserKey(key SecretKey) bool

func (*DB) FileNotExist

func (db *DB) FileNotExist() bool

func (*DB) GetByAlias

func (db *DB) GetByAlias(alias string) (mimas []*Mima)

GetByAlias 凭 alias 找 mima, 如果找不到就返回 nil.

func (*DB) GetByID

func (db *DB) GetByID(id string) (index int, mima *Mima, err error)

GetByID 凭 id 找 mima. 忽略 index:0. 只有一种错误: 找不到记录. 为什么找不到时要返回错误不返回 nil? 因为后续需要返回错误, 在这里集中处理更方便.

func (*DB) GetByIndex

func (db *DB) GetByIndex(i int) *Mima

GetByIndex 为了测试方便.

func (*DB) GetFormByID

func (db *DB) GetFormByID(id string) *MimaForm

GetFormByID 凭 id 找 mima 并转换为有 History 的 MimaForm.

func (*DB) GetFormsByAlias

func (db *DB) GetFormsByAlias(alias string) (forms []*MimaForm)

GetFormsByAlias 凭 alias 找 mima, 并转换为 MimaForm 返回.

func (*DB) GetSettings

func (db *DB) GetSettings() string

GetSettings 返回本软件的一些设定 (json 格式, 且已被 base64 编码). 利用了 The First Mima 的 Notes 来保存设定. 主要用于云备份.

func (*DB) GetTarballPaths

func (db *DB) GetTarballPaths() ([]string, error)

getTarballPaths 返回备份文件的完整路径, 从小到大排序.

func (*DB) HasSettings

func (db *DB) HasSettings() bool

func (*DB) Init

func (db *DB) Init(userKey *SecretKey) error

Init 生成第一条记录, 用于保存密码. 第一条记录的 ID 特殊处理, 手动设置为空字符串. 同时会生成数据库文件 DB.FullPath

func (*DB) IsExpired

func (db *DB) IsExpired() bool

func (*DB) IsNotInit

func (db *DB) IsNotInit() bool

func (*DB) Key

func (db *DB) Key(i int) *SecretKey

Key 根据 i 选择不同的 key. 因为第 0 个 mima 是特殊的, 采用不同的 key.

func (*DB) Len

func (db *DB) Len() int

func (*DB) MimaTable

func (db *DB) MimaTable() []*Mima

MimaTable 为了测试方便.

func (*DB) ReadMimaTable

func (db *DB) ReadMimaTable() (buf bytes.Buffer, err error)

ReadMimaTable 读取内存数据库中的 mimaTable, 把每个 mima 加密并转换为 base64 字符串, 通过 buf 输出. 主要用于云备份.

func (*DB) Rebuild

func (db *DB) Rebuild(userKey *SecretKey) (tarballFile string, err error)

Rebuild 填充内存数据库,读取数据库碎片, 整合到数据库文件中. 每次启动程序, 初始化时, 如果已有账号, 自动执行一次 Rebuild. 为了方便测试返回 tarball 文件路径.

func (*DB) Reset

func (db *DB) Reset()

func (*DB) TrashByID

func (db *DB) TrashByID(id string) error

TrashByID 软删除一个 mima, 并生成一块数据库碎片.

func (*DB) UnDeleteByID

func (db *DB) UnDeleteByID(id string) (err error)

UnDeleteByID 从回收站中还原一个 mima (DeletedAt 重置为零), 并生成一块数据库碎片. 此时, 需要判断 Alias 有无冲突, 如有冲突则清空本条记录的 Alias.

func (*DB) Update

func (db *DB) Update(form *MimaForm) (err error)

Update 根据 MimaForm 更新对应的 Mima 内容, 并生成一块数据库碎片.

func (*DB) UpdateSettings

func (db *DB) UpdateSettings(settings string) error

UpdateSettings 利用 The First Mima 的 Notes 来保存程序的设定, 主要用于云备份. settings 应采用 json 格式, 并且转为 base64 字符串.

func (*DB) UserKey

func (db *DB) UserKey() SecretKey

func (*DB) WriteDBFileFromReader

func (db *DB) WriteDBFileFromReader(data io.ReadCloser, password string, settings string) error

WriteDBFileFromReader 主要用于把从云端下载回来的数据写到本地文件里. 此时, 必须更新 settings 以确保下次上传到云端时不会覆盖原文件. 在本函数内不关闭 data, 应在外层关闭.

type History

type History struct {
	Title    string
	Username string
	Password string
	Notes    string

	// 考虑到实际使用情景, 在一个 mima 的历史记录里面,
	// DateTime 应该是唯一的 (同一条记录不可能同时修改两次).
	DateTime string
}

History 用来保存修改历史. 全部内容均直接保留当时的 Mima 内容, 不作任何修改.

type Mima

type Mima struct {

	// (主键) (必须) (唯一)
	// 由于根据实际使用的性能要求, 采用足以避免重复的算法, 因此平时可偷懒不检查其唯一性.
	ID string

	// 标题 (必须)
	// 第一条记录的 Title 长度为零, 其他记录要求 Title 长度大于零.
	Title string

	// 别名, 用于辅助快速搜索 (允许重复)
	// 多个条目共用同一个别名, 可模拟一个条目拥有多个密码的情形.
	// 注意从回收站恢复条目时 (把 DeletedAt 重置为零时), 需要检查 Alias 冲突.
	Alias string

	// 一次性随机码, 用于加密 (必须) (唯一)
	// 但鉴于 Nonce 具有足够的长度使随机生成的 nonce 也不用担心重复,
	// 因此平时可偷懒不检查其唯一性.
	Nonce Nonce

	Username  string
	Password  string
	Notes     string
	CreatedAt int64
	UpdatedAt int64
	DeletedAt int64
	Operation Operation

	// 修改历史
	History []*History
}

Mima 用来表示一条记录. 其中, 标题是必须的, Nonce 是必须且唯一的.

func Decrypt

func Decrypt(box64 string, key *SecretKey) (*Mima, error)

Decrypt 从已加密数据中解密出一个 Mima 来. 用于从数据库文件中读取数据进内存数据库 (DB.readFullPath).

func NewMima

func NewMima(title string) (*Mima, error)

NewMima 生成一个新的 mima.

func NewMimaFromForm

func NewMimaFromForm(form *MimaForm) (mima *Mima, err error)

NewMimaFromForm 根据 form 的信息生成一个新的 mima.

func (*Mima) Delete

func (mima *Mima) Delete()

Delete 更新删除时间, 即软删除.

func (*Mima) DeleteHistory

func (mima *Mima) DeleteHistory(datetime string) error

DeleteHistory 彻底删除一条历史记录.

func (*Mima) EqualByUpdatedAt

func (mima *Mima) EqualByUpdatedAt(other *Mima) bool

EqualByUpdatedAt 检查两个 mima 的更新日期是否一致.

func (*Mima) IsDeleted

func (mima *Mima) IsDeleted() bool

func (*Mima) Seal

func (mima *Mima) Seal(key *SecretKey) (string, error)

Seal 先把 mima 转换为 json, 再加密并返回 base64 字节码.

func (*Mima) ToForm

func (mima *Mima) ToForm() *MimaForm

ToFormWithHistory 把 Mima 转换为有 History 的 MimaForm, 主要用于 edit 页面.

func (*Mima) UnDelete

func (mima *Mima) UnDelete()

UnDelete 把删除时间重置为零.

func (*Mima) UpdateFromForm

func (mima *Mima) UpdateFromForm(form *MimaForm) (needChangeIndex bool, needWriteFrag bool, err error)

UpdateFromForm 以前端传回来的 MimaForm 为准, 更新内存中的条目内容. 如果只有 Alias 发生改变, 则改变 Alias, 但不生成历史记录, 也不移动元素.

func (*Mima) UpdateFromFrag

func (mima *Mima) UpdateFromFrag(fragment *Mima) (needChangeIndex bool)

UpdateFromFrag 以数据库碎片中的内容为准, 更新内存中的条目.

type MimaForm

type MimaForm struct {
	ID        string
	Title     string
	Alias     string
	Username  string
	Password  string
	Notes     string
	CreatedAt string
	UpdatedAt string
	DeletedAt string
	History   []*History
	Err       error
	Info      error
}

MimaForm 用前端显示一个 Mima.

func (*MimaForm) HideSecrets

func (form *MimaForm) HideSecrets() *MimaForm

HideSecret 删除密码, 备注以及历史记录等敏感信息, 用于不需要展示密码的页面 (为了提高安全性).

func (*MimaForm) IsDeleted

func (form *MimaForm) IsDeleted() bool

IsDeleted 检查该 form 所对应的 mima 是否已被软删除.

type Nonce

type Nonce = [NonceSize]byte

type Operation

type Operation int

Operation 表示数据库的操作指令. 由于本程序不使用真正的数据库, 而是自己弄一个简陋的数据库, 因此需要该类型辅助.

const (
	Insert Operation = iota + 1
	Update
	SoftDelete
	UnDelete
	DeleteForever
)

数据库操作的 enum (枚举)

type SecretKey

type SecretKey = [KeySize]byte

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL