├── CHANGELOG ├── internal ├── must │ ├── test.txt │ ├── must.go │ └── must_test.go ├── entity │ └── kventity.go ├── database │ └── database.go ├── kvpath │ ├── kvgetpath_test.go │ └── kvgetpath.go ├── version │ └── version.go └── secutiry │ └── rsa_util.go ├── .github ├── RELEASE-TEMPLATE.md ├── FUNDING.yaml ├── holopin.yml ├── workflows │ ├── typo-check.yaml │ ├── codeql.yml │ ├── update_contributors.yml │ ├── lint.yaml │ └── ci-cd.yaml ├── ISSUE_TEMPLATE │ ├── discussion.md │ ├── bug_report.md │ └── feature_request.md ├── dependabot.yaml ├── ISSUE_TEMPLATE.md └── PULL_REQUEST_TEMPLATE.md ├── assets ├── cobra.png ├── demo.gif ├── logo.png ├── gopher.png ├── kv-logo.png ├── nutsdb.png └── kvstok-logo.png ├── CONTRIBUTORS.md ├── Makefile ├── Dockerfile ├── .gitignore ├── .golangci.yaml ├── SECURITY.md ├── CONTRIBUTING.md ├── cmd ├── commands │ ├── del.go │ ├── get.go │ ├── list.go │ ├── add.go │ ├── ttl.go │ ├── export.go │ └── import.go └── root.go ├── main.go ├── go.mod ├── .goreleaser.yaml ├── runversion ├── DCO ├── safer-golangci-lint.yml ├── go.sum ├── CODE_OF_CONDUCT.md ├── README.md ├── run └── LICENSE /CHANGELOG: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /internal/must/test.txt: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /.github/RELEASE-TEMPLATE.md: -------------------------------------------------------------------------------- 1 | # Announcements 2 | * First announcement -------------------------------------------------------------------------------- /assets/cobra.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/waldirborbajr/kvstok/HEAD/assets/cobra.png -------------------------------------------------------------------------------- /assets/demo.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/waldirborbajr/kvstok/HEAD/assets/demo.gif -------------------------------------------------------------------------------- /assets/logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/waldirborbajr/kvstok/HEAD/assets/logo.png -------------------------------------------------------------------------------- /assets/gopher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/waldirborbajr/kvstok/HEAD/assets/gopher.png -------------------------------------------------------------------------------- /assets/kv-logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/waldirborbajr/kvstok/HEAD/assets/kv-logo.png -------------------------------------------------------------------------------- /assets/nutsdb.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/waldirborbajr/kvstok/HEAD/assets/nutsdb.png -------------------------------------------------------------------------------- /assets/kvstok-logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/waldirborbajr/kvstok/HEAD/assets/kvstok-logo.png -------------------------------------------------------------------------------- /internal/entity/kventity.go: -------------------------------------------------------------------------------- 1 | package entity 2 | 3 | // Struct to store key/value 4 | type KVStok struct { 5 | Key string 6 | Val string 7 | } 8 | -------------------------------------------------------------------------------- /.github/FUNDING.yaml: -------------------------------------------------------------------------------- 1 | # These are supported funding model platforms 2 | github: [waldirborbajr] 3 | patreon: [waldirborbajr] 4 | ko_fi: waldirborbajunior 5 | -------------------------------------------------------------------------------- /CONTRIBUTORS.md: -------------------------------------------------------------------------------- 1 | # Contributors 2 | 3 | Shout out to our top contributors! 4 | 5 | - [waldirborbajr](https://api.github.com/users/waldirborbajr) 6 | - [dependabot[bot]](https://api.github.com/users/dependabot%5Bbot%5D) 7 | -------------------------------------------------------------------------------- /internal/database/database.go: -------------------------------------------------------------------------------- 1 | package database 2 | 3 | import ( 4 | "github.com/nutsdb/nutsdb" 5 | ) 6 | 7 | const ( 8 | DBName = ".6B7673" // -> .kvs 9 | Bucket = "kvstok" 10 | ) 11 | 12 | // Reference of database 13 | var DB *nutsdb.DB 14 | -------------------------------------------------------------------------------- /.github/holopin.yml: -------------------------------------------------------------------------------- 1 | organization: waldirborbajr # org name on holopin 2 | defaultSticker: cla3akind199908mqwq5zssov # sticker ID 3 | stickers: 4 | - 5 | id: cla3akind199908mqwq5zssov # sticker id 6 | alias: Surfer-Moby-Dock_from-docker # shorthand-string 7 | -------------------------------------------------------------------------------- /.github/workflows/typo-check.yaml: -------------------------------------------------------------------------------- 1 | name: Typo Check 2 | 3 | on: [workflow_call] 4 | 5 | jobs: 6 | typocheck: 7 | name: "Typo Check" 8 | runs-on: ubuntu-latest 9 | steps: 10 | - uses: actions/checkout@v6 11 | 12 | - name: typos-action 13 | uses: crate-ci/typos@v1.39.2 -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env make -f 2 | 3 | test: 4 | go test -v -timeout=1s -race -covermode=atomic -count=1 ./... 5 | 6 | build: test 7 | go build -o ./bin/kvstok ./cmd/cli/main.go 8 | 9 | run: build 10 | ./bin/kvstok 11 | 12 | update: 13 | go get -u all 14 | 15 | 16 | .PHONY: test build 17 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/discussion.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Discussion 3 | about: Begin a discussion 4 | title: '' 5 | labels: '' 6 | assignees: '' 7 | 8 | --- 9 | 10 | **Topic** 11 | A clear and concise description of what you want to discuss 12 | 13 | **Your thoughts** 14 | What you have to say about the topic 15 | -------------------------------------------------------------------------------- /internal/kvpath/kvgetpath_test.go: -------------------------------------------------------------------------------- 1 | package kvpath 2 | 3 | import ( 4 | "testing" 5 | ) 6 | 7 | func TestGetKvPath(t *testing.T) { 8 | path := GetKVPath() 9 | 10 | if path == "" { 11 | t.Fatal("Error getting path") 12 | } 13 | } 14 | 15 | func TestGetKVHomeDir(t *testing.T) { 16 | path := GetKVHomeDir() 17 | 18 | if path == "" { 19 | t.Fatal("Error getting home directory") 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /internal/must/must.go: -------------------------------------------------------------------------------- 1 | package must 2 | 3 | import ( 4 | "fmt" 5 | "os" 6 | ) 7 | 8 | // Fail code 9 | const FAILURE = 1 10 | 11 | // Check if error and exit the program 12 | func Must(err error, message string) { 13 | if err != nil { 14 | 15 | fmt.Fprintf(os.Stderr, "SYSTEM ERROR: %s \n", message) 16 | fmt.Fprintf(os.Stderr, "DEBUG ERROR: %s \n", err.Error()) 17 | os.Exit(FAILURE) 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /Dockerfile: -------------------------------------------------------------------------------- 1 | FROM alpine:3.13 2 | 3 | ENV PATH=/app/:$PATH 4 | 5 | ENV LANG=en_US.UTF-8 \ 6 | LANGUAGE=en_US.UTF-8 7 | 8 | RUN apk add --update --no-cache \ 9 | tzdata \ 10 | htop \ 11 | && cp /usr/share/zoneinfo/America/Sao_Paulo /etc/localtime \ 12 | && echo "America/Sao_Paulo" > /etc/timezone 13 | 14 | WORKDIR /app 15 | 16 | COPY kvstok /app 17 | 18 | ENTRYPOINT ["/app/kvstok"] 19 | CMD ["/bin/sh"] 20 | # 21 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Binaries for programs and plugins 2 | *.exe 3 | *.exe~ 4 | *.dll 5 | *.so 6 | *.dylib 7 | 8 | # Test binary, built with `go test -c` 9 | *.test 10 | 11 | # Output of the go coverage tool, specifically when used with LiteIDE 12 | *.out 13 | 14 | # Dependency directories (remove the comment below to include it) 15 | # vendor/ 16 | 17 | **/.DS_Store 18 | internal/database/0.dat 19 | 20 | **/certs/*.pem 21 | 22 | **bin/ 23 | -------------------------------------------------------------------------------- /internal/must/must_test.go: -------------------------------------------------------------------------------- 1 | package must 2 | 3 | import ( 4 | "os" 5 | "testing" 6 | 7 | "github.com/stretchr/testify/assert" 8 | "github.com/stretchr/testify/require" 9 | ) 10 | 11 | func TestMustRequire(t *testing.T) { 12 | _, err := os.OpenFile("mock.txt", os.O_APPEND, 0600) 13 | require.Equal(t, "open mock.txt: no such file or directory", err.Error()) 14 | 15 | } 16 | 17 | func TestMustAssert(t *testing.T) { 18 | _, err := os.OpenFile("./test.txt", os.O_CREATE, 0600) 19 | assert.Equal(t, err, (nil)) 20 | 21 | } 22 | -------------------------------------------------------------------------------- /.golangci.yaml: -------------------------------------------------------------------------------- 1 | run: 2 | timeout: 5m 3 | tests: false 4 | 5 | issues: 6 | include: 7 | - EXC0001 8 | - EXC0005 9 | - EXC0011 10 | - EXC0012 11 | - EXC0013 12 | 13 | max-issues-per-linter: 0 14 | max-same-issues: 0 15 | 16 | linters: 17 | enable: 18 | - bodyclose 19 | - exportloopref 20 | - goimports 21 | - gosec 22 | - nilerr 23 | - predeclared 24 | - revive 25 | - rowserrcheck 26 | - sqlclosecheck 27 | - tparallel 28 | - unconvert 29 | - unparam 30 | - whitespace 31 | -------------------------------------------------------------------------------- /SECURITY.md: -------------------------------------------------------------------------------- 1 | # Security Policy 2 | 3 | ## Supported Versions 4 | 5 | Use this section to tell people about which versions of your project are 6 | currently being supported with security updates. 7 | 8 | | Version | Supported | 9 | | ------- | ------------------ | 10 | | 5.1.x | :white_check_mark: | 11 | | 5.0.x | :x: | 12 | | 4.0.x | :white_check_mark: | 13 | | < 4.0 | :x: | 14 | 15 | ## Reporting a Vulnerability 16 | 17 | Use this section to tell people how to report a vulnerability. 18 | 19 | Tell them where to go, how often they can expect to get an update on a 20 | reported vulnerability, what to expect if the vulnerability is accepted or 21 | declined, etc. 22 | -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | # Contributing guidelines are as follows: 2 | 3 | 0. Star this repository and follow me 4 | 1. Fork this repository 5 | 2. Clone forked repository onto your system using the command - `git clone [url of forked repository]` 6 | 3. Create a new branch using the command - `git branch [branch-name]` 7 | 4. Move to newly created branch using the command - `git checkout [branch-name]` 8 | 5. Make changes 9 | 6. Add your changes using the command - `git add -A` 10 | 7. Commit your changes using the command - `git commit -m "your commit message"` 11 | 8. Push your committed changes using the command - `git push origin [branch-name]` 12 | 9. Create a pull request 13 | 10. Star this repository 14 | 15 | # For reference watch the following tutorial: 16 | 17 | https://www.youtube.com/watch?v=c6b6B9oN4Vg 18 | -------------------------------------------------------------------------------- /.github/dependabot.yaml: -------------------------------------------------------------------------------- 1 | version: 2 2 | updates: 3 | # Maintain dependencies for GitHub Actions 4 | - package-ecosystem: "github-actions" 5 | directory: "/.github/workflows" 6 | schedule: 7 | interval: "weekly" 8 | # day: "saturday" 9 | # time: "00:01" 10 | timezone: "America/Sao_Paulo" 11 | reviewers: 12 | - "waldirborbajr" 13 | open-pull-requests-limit: 99 14 | commit-message: 15 | prefix: "workflows: " 16 | 17 | - package-ecosystem: "gomod" 18 | directory: "/" 19 | schedule: 20 | interval: weekly 21 | # day: "saturday" 22 | # time: "00:01" 23 | timezone: "America/Sao_Paulo" 24 | allowed_updates: 25 | - match: 26 | update_type: "security" 27 | reviewers: 28 | - "waldirborbajr" 29 | commit-message: 30 | prefix: "build: " 31 | -------------------------------------------------------------------------------- /cmd/commands/del.go: -------------------------------------------------------------------------------- 1 | package commands 2 | 3 | import ( 4 | "github.com/nutsdb/nutsdb" 5 | "github.com/spf13/cobra" 6 | "github.com/waldirborbajr/kvstok/internal/database" 7 | "github.com/waldirborbajr/kvstok/internal/must" 8 | ) 9 | 10 | // DelCmd represents the delkv command 11 | var DelCmd = &cobra.Command{ 12 | Use: "{d}elkv [KEY]", 13 | Short: "Remove a stored key.", 14 | Long: ``, 15 | Aliases: []string{"d"}, 16 | Args: cobra.MinimumNArgs(1), 17 | Run: func(cmd *cobra.Command, args []string) { 18 | if err := database.DB.Update( 19 | func(tx *nutsdb.Tx) error { 20 | key := []byte(args[0]) 21 | return tx.Delete(database.Bucket, key) 22 | }); err != nil { 23 | must.Must(err, "DelCmd() - oops! Huston, we have a problem deleting keys. The key does not exist or dataase must be empty.") 24 | } 25 | }, 26 | } 27 | -------------------------------------------------------------------------------- /cmd/commands/get.go: -------------------------------------------------------------------------------- 1 | package commands 2 | 3 | import ( 4 | "fmt" 5 | 6 | "github.com/nutsdb/nutsdb" 7 | "github.com/spf13/cobra" 8 | "github.com/waldirborbajr/kvstok/internal/database" 9 | "github.com/waldirborbajr/kvstok/internal/must" 10 | ) 11 | 12 | // GetCmd represents the getkv command 13 | var GetCmd = &cobra.Command{ 14 | Use: "{g}etkv [KEY]", 15 | Short: "Get a value for a key.", 16 | Long: ``, 17 | Aliases: []string{"g"}, 18 | Args: cobra.MinimumNArgs(1), 19 | Run: func(cmd *cobra.Command, args []string) { 20 | // nolint:staticcheck 21 | if err := database.DB.Update( 22 | func(tx *nutsdb.Tx) error { 23 | key := []byte(args[0]) 24 | content, err := tx.Get(database.Bucket, key) 25 | must.Must(err, "GetCmd() - key not found or datababse must be empty.") 26 | fmt.Printf("%s\n", content) 27 | return nil 28 | }); err != nil { 29 | } 30 | }, 31 | } 32 | -------------------------------------------------------------------------------- /.github/workflows/codeql.yml: -------------------------------------------------------------------------------- 1 | name: Code Scanning 2 | 3 | on: 4 | push: 5 | branches: [main] 6 | pull_request: 7 | branches: [main] 8 | paths-ignore: 9 | - '**/*.md' 10 | schedule: 11 | - cron: "0 0 * * 0" 12 | 13 | permissions: 14 | actions: read # for github/codeql-action/init to get workflow details 15 | contents: read # for actions/checkout to fetch code 16 | security-events: write # for github/codeql-action/analyze to upload SARIF results 17 | 18 | jobs: 19 | CodeQL-Build: 20 | runs-on: ubuntu-latest 21 | 22 | steps: 23 | - name: Check out code 24 | uses: actions/checkout@v6 25 | 26 | - name: Initialize CodeQL 27 | uses: github/codeql-action/init@v4 28 | with: 29 | languages: go 30 | queries: security-and-quality 31 | 32 | - name: Perform CodeQL Analysis 33 | uses: github/codeql-action/analyze@v4 34 | -------------------------------------------------------------------------------- /cmd/commands/list.go: -------------------------------------------------------------------------------- 1 | package commands 2 | 3 | import ( 4 | "fmt" 5 | 6 | "github.com/nutsdb/nutsdb" 7 | "github.com/spf13/cobra" 8 | "github.com/waldirborbajr/kvstok/internal/database" 9 | "github.com/waldirborbajr/kvstok/internal/must" 10 | ) 11 | 12 | // LstCmd represents the lstkv command 13 | var LstCmd = &cobra.Command{ 14 | Use: "{l}istkv", 15 | Short: "List all keys values pairs.", 16 | Long: ``, 17 | Aliases: []string{"l"}, 18 | Run: func(cmd *cobra.Command, args []string) { 19 | err := database.DB.View( 20 | func(tx *nutsdb.Tx) error { 21 | if keys, values, err := tx.GetAll(database.Bucket); err != nil { 22 | return err 23 | } else { 24 | n := len(keys) 25 | for i := 0; i < n; i++ { 26 | fmt.Println(string(keys[i]), " ", string(values[i])) 27 | } 28 | } 29 | 30 | return nil 31 | }) 32 | 33 | must.Must(err, "LstCmd() - key not found or datababse must be empty.") 34 | }, 35 | } 36 | -------------------------------------------------------------------------------- /cmd/commands/add.go: -------------------------------------------------------------------------------- 1 | package commands 2 | 3 | import ( 4 | "errors" 5 | 6 | "github.com/nutsdb/nutsdb" 7 | "github.com/spf13/cobra" 8 | "github.com/waldirborbajr/kvstok/internal/database" 9 | "github.com/waldirborbajr/kvstok/internal/must" 10 | ) 11 | 12 | // AddCmd represents the addkv command 13 | var AddCmd = &cobra.Command{ 14 | Use: "{a}ddkv [KEY] [VALUE]", 15 | Short: "Add or Update a value for a key.", 16 | Long: ``, 17 | Aliases: []string{"a"}, 18 | Args: func(cmd *cobra.Command, args []string) error { 19 | if len(args) < 2 { 20 | return errors.New("addkv requires two parameters [key] and [value]. Please try it again") 21 | } 22 | return nil 23 | }, 24 | Run: func(cmd *cobra.Command, args []string) { 25 | err := database.DB.Update( 26 | func(tx *nutsdb.Tx) error { 27 | return tx.Put(database.Bucket, []byte(args[0]), []byte(args[1]), 0) 28 | }) 29 | 30 | must.Must(err, "AddCmd() - oops! Huston, we have a problem adding/updating keys.") 31 | }, 32 | } 33 | -------------------------------------------------------------------------------- /.github/workflows/update_contributors.yml: -------------------------------------------------------------------------------- 1 | name: Update CONTRIBUTORS file 2 | on: 3 | schedule: 4 | - cron: "0 0 1 * *" 5 | workflow_dispatch: 6 | jobs: 7 | main: 8 | runs-on: ubuntu-latest 9 | steps: 10 | - uses: actions/checkout@v6 11 | - uses: minicli/action-contributors@v3 12 | name: "Update a projects CONTRIBUTORS file" 13 | env: 14 | CONTRIB_REPOSITORY: 'waldirborbajr/kvstok' 15 | CONTRIB_OUTPUT_FILE: 'CONTRIBUTORS.md' 16 | - name: Create a PR 17 | uses: peter-evans/create-pull-request@v7 18 | with: 19 | commit-message: Update Contributors 20 | title: "[automated] Update Contributors File" 21 | token: ${{ secrets.GITHUB_TOKEN }} 22 | 23 | # - name: Update resources 24 | # uses: test-room-7/action-update-file@v1 25 | # with: 26 | # file-path: 'CONTRIBUTORS.md' 27 | # commit-msg: Update Contributors 28 | # github-token: ${{ secrets.GITHUB_TOKEN }} 29 | -------------------------------------------------------------------------------- /internal/version/version.go: -------------------------------------------------------------------------------- 1 | package version 2 | 3 | const ( 4 | UnknownVersion = "unknown" 5 | ProtocolVersion = "v0.4.0" 6 | ) 7 | 8 | // provided at compile time 9 | var ( 10 | GitCommit string // long commit hash of source tree, e.g. "0b5ed7a" 11 | GitBranch string // current branch name the code is built off, e.g. "master" 12 | GitTag string // current tag name the code is built off, e.g. "v1.5.0" 13 | GitSummary string // output of "git describe --tags --dirty --always", e.g. "4cb95ca-dirty" 14 | GitState string // whether there are uncommitted changes, e.g. "clean" or "dirty" 15 | BuildDate string // RFC3339 formatted UTC date, e.g. "2016-08-04T18:07:54Z" 16 | Version string // contents of ./VERSION file, if exists 17 | GoVersion string // the version of go, e.g. "go version go1.10.3 darwin/amd64" 18 | ) 19 | 20 | func AppVersion() string { 21 | if GitTag != "" { 22 | return GitTag 23 | } else if Version != "" { 24 | return Version 25 | } 26 | 27 | return UnknownVersion 28 | } 29 | -------------------------------------------------------------------------------- /main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "os" 6 | 7 | "github.com/waldirborbajr/kvstok/cmd" 8 | "github.com/waldirborbajr/kvstok/internal/kvpath" 9 | security "github.com/waldirborbajr/kvstok/internal/secutiry" 10 | ) 11 | 12 | var ( 13 | hasPub = true 14 | hasPriv = true 15 | ) 16 | 17 | func main() { 18 | home := kvpath.GetKVHomeDir() 19 | 20 | pub := home + "/.config/kvstok/kvstok.pub" 21 | priv := home + "/.config/kvstok/kvstok.priv" 22 | 23 | if _, err := os.Stat(pub); err != nil { 24 | hasPub = false 25 | } 26 | 27 | if _, err := os.Stat(priv); err != nil { 28 | hasPriv = false 29 | } 30 | 31 | // Generete PRIV/PUB RSA Key 32 | if !hasPub && !hasPriv { 33 | 34 | fmt.Println("Generating RSA priv/pub keys pairing") 35 | privateKey, publicKey := security.RSA_GenerateKey(4096) 36 | 37 | _ = os.WriteFile(pub, []byte(security.PublicKeyToBytes(publicKey)), 0600) 38 | _ = os.WriteFile(priv, []byte(security.PrivateKeyToBytes(privateKey)), 0600) 39 | } 40 | 41 | cmd.Execute() 42 | } 43 | -------------------------------------------------------------------------------- /go.mod: -------------------------------------------------------------------------------- 1 | module github.com/waldirborbajr/kvstok 2 | 3 | go 1.25 4 | 5 | require ( 6 | github.com/nutsdb/nutsdb v1.0.4 7 | github.com/spf13/cobra v1.10.1 8 | github.com/stretchr/testify v1.10.0 9 | ) 10 | 11 | require ( 12 | github.com/antlabs/stl v0.0.2 // indirect 13 | github.com/antlabs/timer v0.1.4 // indirect 14 | github.com/bwmarrin/snowflake v0.3.0 // indirect 15 | github.com/davecgh/go-spew v1.1.1 // indirect 16 | github.com/gofrs/flock v0.12.1 // indirect 17 | github.com/inconshreveable/mousetrap v1.1.0 // indirect 18 | github.com/kr/text v0.2.0 // indirect 19 | github.com/pkg/errors v0.9.1 // indirect 20 | github.com/pmezard/go-difflib v1.0.0 // indirect 21 | github.com/rogpeppe/go-internal v1.13.1 // indirect 22 | github.com/spf13/pflag v1.0.9 // indirect 23 | github.com/tidwall/btree v1.7.0 // indirect 24 | github.com/xujiajun/mmap-go v1.0.1 // indirect 25 | github.com/xujiajun/utils v0.0.0-20220904132955-5f7c5b914235 // indirect 26 | golang.org/x/sys v0.25.0 // indirect 27 | gopkg.in/yaml.v3 v3.0.1 // indirect 28 | ) 29 | -------------------------------------------------------------------------------- /internal/kvpath/kvgetpath.go: -------------------------------------------------------------------------------- 1 | package kvpath 2 | 3 | import ( 4 | "crypto/sha256" 5 | "encoding/hex" 6 | "io" 7 | "log" 8 | "os" 9 | 10 | "github.com/waldirborbajr/kvstok/internal/must" 11 | ) 12 | 13 | // Get current path and returns 14 | func GetKVPath() string { 15 | pwd, err := os.Executable() 16 | must.Must(err, "GetKVPath() - getting current path.") 17 | 18 | return pwd 19 | } 20 | 21 | // Get $HOME path of user and returns 22 | func GetKVHomeDir() string { 23 | home, err := os.UserHomeDir() 24 | must.Must(err, "GetKVHomeDir() - getting $HOME path.") 25 | 26 | return home 27 | } 28 | 29 | // Generate HASH of a given file 30 | func GenHash(filename string) string { 31 | f, err := os.Open(filename) 32 | must.Must(err, "GenHash() - generating Hashcode") 33 | defer func() { 34 | if err := f.Close(); err != nil { 35 | log.Printf("Error closing file: %s\n", err) 36 | } 37 | }() 38 | 39 | hasher := sha256.New() 40 | if _, err := io.Copy(hasher, f); err != nil { 41 | log.Fatal(err) 42 | } 43 | return hex.EncodeToString(hasher.Sum(nil)) 44 | } 45 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE.md: -------------------------------------------------------------------------------- 1 | PLEASE READ 2 | ------------- 3 | 4 | DO NOT submit tickets without _first_ using the latest version of Golang, clearing your local golang package cache, and re-building mockery using the _latest_ Golang version and the _latest_ version of mockery. Please provide evidence this has been done in your issue. Failure to provide this evidence will likely result in your issue being closed. 5 | 6 | Description 7 | ------------- 8 | 9 | [Description of the bug or feature] 10 | 11 | Mockery Version 12 | -------- 13 | 14 | [version of mockery being used] 15 | 16 | Golang Version 17 | -------------- 18 | 19 | [version of golang being used] 20 | 21 | ``` 22 | NOTE: Please upgrade to the latest golang version before submitting tickets! 23 | ``` 24 | 25 | Installation Method 26 | ------------------- 27 | 28 | - [ ] Binary Distribution 29 | - [ ] Docker 30 | - [ ] brew 31 | - [ ] go install 32 | - [ ] Other: [specify] 33 | 34 | Steps to Reproduce 35 | ------------------ 36 | 37 | 1. [First Step] 38 | 2. [Second Step] 39 | 3. [etc] 40 | 41 | ### Expected Behavior 42 | 43 | [what you expect to happen] 44 | 45 | ### Actual Behavior 46 | 47 | [what actually happened] 48 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/bug_report.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Bug report 3 | about: Create a report to help us improve 4 | title: '' 5 | labels: bug 6 | assignees: '' 7 | 8 | --- 9 | 10 | **Describe the bug** 11 | A clear and concise description of what the bug is. 12 | 13 | **To Reproduce** 14 | Steps to reproduce the behavior: 15 | 16 | 1. Go to '...' 17 | 2. Click on '....' 18 | 3. Scroll down to '....' 19 | 4. See error 20 | 21 | **Expected behavior** 22 | A clear and concise description of what you expected to happen. 23 | 24 | **Screenshots** 25 | If applicable, add screenshots to help explain your problem. 26 | 27 | **Version info:** 28 | _Run `lazygit --version` and paste the result here_ 29 | _Run `git --version` and paste the result here_ 30 | 31 | **Additional context** 32 | Add any other context about the problem here. 33 | 34 | **Note:** please try updating to the latest version or [manually building](https://github.com/jesseduffield/lazygit/#manual) the latest `master` to see if the issue still occurs. 35 | 36 | 39 | -------------------------------------------------------------------------------- /.github/PULL_REQUEST_TEMPLATE.md: -------------------------------------------------------------------------------- 1 | Description 2 | ------------- 3 | 4 | Please include a summary of the changes and the related issue. Please also include relevant motivation and context. 5 | 6 | - Fixes # (issue) 7 | 8 | ## Type of change 9 | 10 | - [ ] Bug fix (non-breaking change which fixes an issue) 11 | - [ ] New feature (non-breaking change which adds functionality) 12 | - [ ] Breaking change (fix or feature that would cause existing functionality to not work as expected) 13 | - [ ] This change requires a documentation update 14 | 15 | Version of Golang used when building/testing: 16 | --------------------------------------------- 17 | 18 | - [ ] 1.17 19 | - [ ] 1.18 20 | - [ ] 1.19 21 | 22 | How Has This Been Tested? 23 | --------------------------- 24 | 25 | Please describe the tests that you ran to verify your changes. Provide instructions so we can reproduce. Please also list any relevant details for your test configuration 26 | 27 | Checklist 28 | ----------- 29 | 30 | - [ ] My code follows the style guidelines of this project 31 | - [ ] I have performed a self-review of my code 32 | - [ ] I have commented my code, particularly in hard-to-understand areas 33 | - [ ] I have made corresponding changes to the documentation 34 | - [ ] My changes generate no new warnings 35 | - [ ] I have added tests that prove my fix is effective or that my feature works 36 | - [ ] New and existing unit tests pass locally with my changes 37 | -------------------------------------------------------------------------------- /cmd/commands/ttl.go: -------------------------------------------------------------------------------- 1 | package commands 2 | 3 | import ( 4 | "errors" 5 | "strconv" 6 | 7 | "github.com/nutsdb/nutsdb" 8 | "github.com/spf13/cobra" 9 | "github.com/waldirborbajr/kvstok/internal/database" 10 | "github.com/waldirborbajr/kvstok/internal/must" 11 | ) 12 | 13 | // AddCmd represents the addkv command 14 | var TtlCmd = &cobra.Command{ 15 | Use: "{t}tladdkv [KEY] [VALUE] [TIME_TO_LIVE_IN_MINUTES]", 16 | Short: "Add a key with time to be live. Default 1 minute.", 17 | Long: ``, 18 | Aliases: []string{"t"}, 19 | Args: func(cmd *cobra.Command, args []string) error { 20 | if len(args) < 2 { 21 | return errors.New("addkv requires at least two parameters [key] and [value] the param [ttl] it is optional, the default value it is 1 minute. Please try it again") 22 | } 23 | return nil 24 | }, 25 | Run: func(cmd *cobra.Command, args []string) { 26 | if err := database.DB.Update( 27 | func(tx *nutsdb.Tx) error { 28 | key := []byte(args[0]) 29 | val := []byte(args[1]) 30 | ttl := uint32(60) 31 | 32 | if len(args) == 3 { 33 | temp_ttl, err := strconv.ParseUint(string([]byte(args[2])), 10, 32) 34 | must.Must(err, "Third param must be a number.") 35 | ttl = uint32(temp_ttl) * 60 36 | } 37 | 38 | return tx.Put(database.Bucket, key, val, ttl) 39 | }); err != nil { 40 | must.Must(err, "TTLCmd() - oops! Huston, we have a problem adding/updating keys.") 41 | } 42 | }, 43 | } 44 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/feature_request.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Feature request 3 | about: Suggest an idea for this project 4 | title: '' 5 | labels: enhancement 6 | assignees: '' 7 | 8 | --- 9 | 10 | **Is your feature request related to a problem? Please describe.** 11 | A clear and concise description of what the problem is. Ex. I'm always frustrated when [...] 12 | 13 | **Describe the solution you'd like** 14 | A clear and concise description of what you want to happen. 15 | 16 | **Describe alternatives you've considered** 17 | A clear and concise description of any alternative solutions or features you've considered. 18 | 19 | **Additional context** 20 | Add any other context or screenshots about the feature request here. 21 | 22 | 31 | -------------------------------------------------------------------------------- /cmd/commands/export.go: -------------------------------------------------------------------------------- 1 | package commands 2 | 3 | import ( 4 | "encoding/json" 5 | "fmt" 6 | "os" 7 | 8 | "github.com/nutsdb/nutsdb" 9 | "github.com/spf13/cobra" 10 | "github.com/waldirborbajr/kvstok/internal/database" 11 | "github.com/waldirborbajr/kvstok/internal/kvpath" 12 | "github.com/waldirborbajr/kvstok/internal/must" 13 | ) 14 | 15 | // LstCmd represents the lstkv command 16 | var ExpCmd = &cobra.Command{ 17 | Use: "{e}xportkv", 18 | Short: "Export all keys to a file.", 19 | Long: ``, 20 | Aliases: []string{"e"}, 21 | Run: func(cmd *cobra.Command, args []string) { 22 | content := make(map[string]string) 23 | err := database.DB.View( 24 | func(tx *nutsdb.Tx) error { 25 | if keys, values, err := tx.GetAll(database.Bucket); err != nil { 26 | return err 27 | } else { 28 | n := len(keys) 29 | for i := 0; i < n; i++ { 30 | fmt.Println(string(keys[i]), " ", string(values[i])) 31 | } 32 | } 33 | 34 | configFile := kvpath.GetKVHomeDir() + "/.config/kvstok/kvstok.json" 35 | configHash := kvpath.GetKVHomeDir() + "/.config/kvstok/kvstok.hash" 36 | 37 | // save to file 38 | fileContent, _ := json.MarshalIndent(content, "", " ") 39 | _ = os.WriteFile(configFile, fileContent, 0600) 40 | 41 | hash := kvpath.GenHash(configFile) 42 | 43 | _ = os.WriteFile(configHash, []byte(hash), 0600) 44 | 45 | return nil 46 | }) 47 | 48 | must.Must(err, "ExpCmd() - oops! Huston, we have a problem exporting keys.") 49 | 50 | fmt.Printf("Keys exported to ~/.config/kvstok \n Please keep [.json and .hash] files it into safety place.") 51 | }, 52 | } 53 | -------------------------------------------------------------------------------- /.goreleaser.yaml: -------------------------------------------------------------------------------- 1 | # This is an example .goreleaser.yml file with some sensible defaults. 2 | # Make sure to check the documentation at https://goreleaser.com 3 | 4 | # The lines below are called `modelines`. See `:help modeline` 5 | # Feel free to remove those if you don't want/need to use them. 6 | # yaml-language-server: $schema=https://goreleaser.com/static/schema.json 7 | # vim: set ts=2 sw=2 tw=0 fo=cnqoj 8 | 9 | version: 1 10 | 11 | before: 12 | hooks: 13 | # You may remove this if you don't use go modules. 14 | - go mod tidy 15 | # you may remove this if you don't need go generate 16 | - go generate ./... 17 | 18 | builds: 19 | - env: 20 | - CGO_ENABLED=0 21 | goos: 22 | - linux 23 | - darwin 24 | 25 | archives: 26 | - format: tar.gz 27 | # this name template makes the OS and Arch compatible with the results of `uname`. 28 | name_template: >- 29 | {{ .ProjectName }}_ 30 | {{- title .Os }}_ 31 | {{- if eq .Arch "amd64" }}x86_64 32 | {{- else if eq .Arch "386" }}i386 33 | {{- else }}{{ .Arch }}{{ end }} 34 | {{- if .Arm }}v{{ .Arm }}{{ end }} 35 | # use zip for windows archives 36 | format_overrides: 37 | - goos: windows 38 | format: zip 39 | 40 | changelog: 41 | sort: asc 42 | filters: 43 | exclude: 44 | - "^docs:" 45 | - "^test:" 46 | 47 | brews: 48 | - name: glink 49 | homepage: "https://github.com/waldirborbajr/glink" 50 | description: "Smart terminal session manager" 51 | license: "MIT" 52 | url_template: "https://github.com/waldirborbajr/glink/releases/download/{{ .Tag }}/{{ .ArtifactName }}" 53 | commit_msg_template: "Brew formula update for {{ .ProjectName }} version {{ .Tag }}" 54 | repository: 55 | owner: waldirborbajr 56 | name: homebrew-glink 57 | branch: main 58 | commit_author: 59 | name: goreleaser-bot 60 | email: bot@goreleaser.com 61 | -------------------------------------------------------------------------------- /runversion: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # 3 | # ref: https://gist.github.com/CSTDev/08c127680e3b5fae38c051da3e489351 4 | # go get -u gitlab.com/waldirborbajr/package-name 5 | 6 | #get highest tag number 7 | VERSION=`git describe --abbrev=0 --tags` 8 | 9 | #replace . with space so can split into an array 10 | VERSION_BITS=(${VERSION//./ }) 11 | 12 | #get number parts and increase last one by 1 13 | VNUM1=${VERSION_BITS[0]} 14 | VNUM2=${VERSION_BITS[1]} 15 | VNUM3=${VERSION_BITS[2]} 16 | VNUM1=`echo $VNUM1 | sed 's/v//'` 17 | 18 | # Check for #major or #minor in commit message and increment the relevant version number 19 | MAJOR=`git log --format=%B -n 1 HEAD | grep '#major'` 20 | MINOR=`git log --format=%B -n 1 HEAD | grep '#minor'` 21 | 22 | if [ "$MAJOR" ]; then 23 | echo "Update major version" 24 | VNUM1=$((VNUM1+1)) 25 | VNUM2=0 26 | VNUM3=0 27 | elif [ "$MINOR" ]; then 28 | echo "Update minor version" 29 | if [ -z "$VNUM1" ]; then 30 | VNUM1=0 31 | fi 32 | VNUM2=$((VNUM2+1)) 33 | VNUM3=0 34 | else 35 | echo "Update patch version" 36 | if [ -z "$VNUM1" ]; then 37 | VNUM1=0 38 | fi 39 | if [ -z "$VNUM2" ]; then 40 | VNUM2=0 41 | fi 42 | VNUM3=$((VNUM3+1)) 43 | fi 44 | 45 | #create new tag 46 | NEW_TAG="v$VNUM1.$VNUM2.$VNUM3" 47 | 48 | echo "Updating $VERSION to $NEW_TAG" 49 | 50 | #get current hash and see if it already has a tag 51 | GIT_COMMIT=`git rev-parse HEAD` 52 | NEEDS_TAG=`git describe --contains $GIT_COMMIT` 53 | # NEEDS_TAG=`git describe --contains $GIT_COMMIT 2>/dev/null` 54 | 55 | #only tag if no tag already (would be better if the git describe command above could have a silent option) 56 | if [ -z "$NEEDS_TAG" ]; then 57 | echo "Tagged with $NEW_TAG (Ignoring fatal:cannot describe - this means commit is untagged) " 58 | git tag -a $NEW_TAG -m "version $VNUM1.$VNUM2.$VNUM3" 59 | git push --tags 60 | else 61 | echo "Already a tag on this commit" 62 | fi 63 | 64 | -------------------------------------------------------------------------------- /.github/workflows/lint.yaml: -------------------------------------------------------------------------------- 1 | name: Lint 2 | on: 3 | push: 4 | paths: 5 | - "**.go" 6 | - go.mod 7 | - go.sum 8 | pull_request: 9 | paths: 10 | - "**.go" 11 | - go.mod 12 | - go.sum 13 | 14 | permissions: 15 | contents: read 16 | 17 | jobs: 18 | lint: 19 | runs-on: ubuntu-latest 20 | 21 | steps: 22 | - name: Set up Go 1.22 23 | uses: actions/setup-go@v5 24 | with: 25 | go-version: 1.22 26 | 27 | - name: Check out code 28 | uses: actions/checkout@v6 29 | 30 | - name: Restore Go modules cache 31 | uses: actions/cache@v4 32 | with: 33 | path: ~/go/pkg/mod 34 | key: go-${{ runner.os }}-${{ hashFiles('go.mod') }} 35 | restore-keys: | 36 | go-${{ runner.os }}- 37 | 38 | - name: Verify dependencies 39 | run: | 40 | go mod verify 41 | go mod download 42 | 43 | LINT_VERSION=1.54.1 44 | curl -fsSL https://github.com/golangci/golangci-lint/releases/download/v${LINT_VERSION}/golangci-lint-${LINT_VERSION}-linux-amd64.tar.gz | \ 45 | tar xz --strip-components 1 --wildcards \*/golangci-lint 46 | mkdir -p bin && mv golangci-lint bin/ 47 | 48 | - name: Run checks 49 | run: | 50 | STATUS=0 51 | assert-nothing-changed() { 52 | local diff 53 | "$@" >/dev/null || return 1 54 | if ! diff="$(git diff -U1 --color --exit-code)"; then 55 | printf '\e[31mError: running `\e[1m%s\e[22m` results in modifications that you must check into version control:\e[0m\n%s\n\n' "$*" "$diff" >&2 56 | git checkout -- . 57 | STATUS=1 58 | fi 59 | } 60 | 61 | assert-nothing-changed go fmt ./... 62 | assert-nothing-changed go mod tidy 63 | 64 | bin/golangci-lint run --out-format=github-actions --timeout=3m || STATUS=$? 65 | 66 | exit $STATUS 67 | -------------------------------------------------------------------------------- /cmd/commands/import.go: -------------------------------------------------------------------------------- 1 | package commands 2 | 3 | import ( 4 | "encoding/json" 5 | "fmt" 6 | "os" 7 | 8 | "github.com/nutsdb/nutsdb" 9 | "github.com/spf13/cobra" 10 | "github.com/waldirborbajr/kvstok/internal/database" 11 | "github.com/waldirborbajr/kvstok/internal/kvpath" 12 | "github.com/waldirborbajr/kvstok/internal/must" 13 | ) 14 | 15 | // AddCmd represents the addkv command 16 | var ImpCmd = &cobra.Command{ 17 | Use: "{i}mportkv", 18 | Short: "Rostore all keys from kvstok.json.", 19 | Long: ``, 20 | Aliases: []string{"i"}, 21 | Run: func(cmd *cobra.Command, args []string) { 22 | var dataResult map[string]string 23 | 24 | configFile := kvpath.GetKVHomeDir() + "/.config/kvstok/kvstok.json" 25 | configHash := kvpath.GetKVHomeDir() + "/.config/kvstok/kvstok.hash" 26 | 27 | // Check export file integrity 28 | file, err := os.ReadFile(configHash) 29 | must.Must(err, "ImpCmd() - oops! Huston, we have a problem importing keys.") 30 | 31 | currentHash := kvpath.GenHash(configFile) 32 | storedHash := []byte(file) 33 | 34 | areEquals := isEquals(currentHash, string(storedHash)) 35 | 36 | if !areEquals { 37 | 38 | fmt.Fprintf(os.Stderr, "JSON export key corrupted. Hashcode are not the same.") 39 | os.Exit(1) 40 | } 41 | 42 | if areEquals { 43 | // Import JSON after integrity check 44 | file, err = os.ReadFile(configFile) 45 | must.Must(err, "ImpCmd() - oops! Huston, we have a problem integrity broken.") 46 | 47 | json.Unmarshal([]byte(file), &dataResult) 48 | 49 | for key, value := range dataResult { 50 | err := database.DB.Update( 51 | func(tx *nutsdb.Tx) error { 52 | key := []byte(key) 53 | val := []byte(value) 54 | return tx.Put(database.Bucket, key, val, 0) 55 | }) 56 | 57 | must.Must(err, "ImpCmd() - oops! Huston, we have a problem integrity broken.") 58 | } 59 | } 60 | 61 | fmt.Printf("Keys imported successfully.") 62 | }, 63 | } 64 | 65 | func isEquals(param1 string, param2 string) bool { 66 | bret := true 67 | 68 | if param1 != param2 { 69 | bret = false 70 | } 71 | 72 | return bret 73 | } 74 | -------------------------------------------------------------------------------- /.github/workflows/ci-cd.yaml: -------------------------------------------------------------------------------- 1 | # cSpell:words jstemmer benchmem goreleaser 2 | name: Test, Build and Publish 3 | 4 | on: 5 | pull_request: 6 | types: [opened, synchronize] 7 | push: 8 | branches: [main] 9 | tags: 10 | - "*" 11 | 12 | permissions: 13 | contents: write 14 | 15 | jobs: 16 | tests: 17 | strategy: 18 | matrix: 19 | os: [ubuntu-latest, macos-latest] 20 | runs-on: ${{ matrix.os }} 21 | steps: 22 | 23 | - uses: actions/setup-go@v5 24 | - uses: actions/checkout@v6 25 | 26 | with: 27 | go-version: "1.22" 28 | - name: Install deps 29 | run: go install github.com/jstemmer/go-junit-report/v2@latest 30 | - name: Run tests 31 | run: go test -v -race ./... -coverprofile=coverage.txt -covermode=atomic -timeout=90s 32 | # run: go test -cover -bench=. -benchmem -race -v 2>&1 ./... | go-junit-report -set-exit-code > report.xml 33 | # - name: Test Summary 34 | # uses: test-summary/action@v2 35 | # with: 36 | # paths: | 37 | # report.xml 38 | # if: always() 39 | 40 | goreleaser: 41 | name: Build and Publish 42 | needs: tests 43 | runs-on: ubuntu-latest 44 | if: github.event_name == 'push' && contains(github.ref, 'refs/tags/') 45 | steps: 46 | - name: Checkout 47 | uses: actions/checkout@v6 48 | with: 49 | fetch-depth: 0 50 | - name: Set up Go 51 | uses: actions/setup-go@v5 52 | with: 53 | go-version: "1.22" 54 | - name: Run GoReleaser 55 | uses: goreleaser/goreleaser-action@v6 56 | with: 57 | distribution: goreleaser 58 | version: latest 59 | args: release --clean 60 | env: 61 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} 62 | 63 | # check_brew: 64 | # name: Check Brew Tap 65 | # needs: goreleaser 66 | # runs-on: macos-latest 67 | # steps: 68 | # - name: Install with brew 69 | # run: | 70 | # brew install waldirborbajr/glink/glink 71 | # TODO: assert the latest version was installed 72 | -------------------------------------------------------------------------------- /cmd/root.go: -------------------------------------------------------------------------------- 1 | package cmd 2 | 3 | import ( 4 | "log" 5 | 6 | "github.com/nutsdb/nutsdb" 7 | "github.com/spf13/cobra" 8 | "github.com/waldirborbajr/kvstok/cmd/commands" 9 | "github.com/waldirborbajr/kvstok/internal/database" 10 | "github.com/waldirborbajr/kvstok/internal/kvpath" 11 | "github.com/waldirborbajr/kvstok/internal/must" 12 | "github.com/waldirborbajr/kvstok/internal/version" 13 | ) 14 | 15 | // Size of database to store key/value 16 | const DBSIZE = 2048 * 2048 17 | 18 | // rootCmd represents the base command when called without any subcommands 19 | var rootCmd = &cobra.Command{ 20 | Use: "kvstok", 21 | Short: "KVStoK is a CLI-based KEY VALUE storage.", 22 | Long: ``, 23 | Version: version.AppVersion(), 24 | } 25 | 26 | // Execute adds all child commands to the root command and sets flags appropriately. 27 | // This is called by main.main(). It only needs to happen once to the rootCmd. 28 | func Execute() { 29 | must.Must(rootCmd.Execute(), "Execute() on parsing commands.") 30 | } 31 | 32 | func init() { 33 | // Import config 34 | initConfig() 35 | 36 | rootCmd.CompletionOptions.HiddenDefaultCmd = true 37 | rootCmd.DisableSuggestions = true 38 | 39 | rootCmd.AddCommand(commands.AddCmd) 40 | rootCmd.AddCommand(commands.DelCmd) 41 | rootCmd.AddCommand(commands.GetCmd) 42 | rootCmd.AddCommand(commands.LstCmd) 43 | rootCmd.AddCommand(commands.ExpCmd) 44 | rootCmd.AddCommand(commands.ImpCmd) 45 | rootCmd.AddCommand(commands.TtlCmd) 46 | } 47 | 48 | func initConfig() { 49 | homePath := kvpath.GetKVHomeDir() + "/.config/kvstok/" + database.DBName 50 | 51 | var err error 52 | 53 | opt := nutsdb.DefaultOptions 54 | opt.SegmentSize = 8 * nutsdb.MB 55 | opt.CommitBufferSize = 4 * nutsdb.MB 56 | opt.MaxBatchSize = (15 * opt.SegmentSize / 4) / 100 57 | opt.MaxBatchCount = (15 * opt.SegmentSize / 4) / 100 / 100 58 | // opt.WithSegmentSize(DBSIZE), 59 | 60 | database.DB, err = nutsdb.Open(opt, nutsdb.WithDir(homePath)) 61 | if err != nil { 62 | log.Fatal(err.Error()) 63 | } 64 | 65 | database.DB.Update(func(tx *nutsdb.Tx) error { 66 | // you should call Bucket with data structure and the name of bucket first 67 | return tx.NewBucket(nutsdb.DataStructureBTree, database.Bucket) 68 | }) 69 | 70 | // defer database.DB.Close() 71 | } 72 | -------------------------------------------------------------------------------- /DCO: -------------------------------------------------------------------------------- 1 | By contributing to this project Git repo, you are deemed to have 2 | accepted the agreement (DCO, or Corporate or Individual CLA attached 3 | below) applicable to your contribution. 4 | 5 | Any merge request, issue posts, commits, comments, wiki updates, and any 6 | other content development and contribution legally constitutes digitally 7 | signed acceptance of the terms in the attached DCO below, meaning that 8 | any contribution to this project -- in any way -- releases any legal 9 | claim on those contributions including copyright, patents, trademarks, 10 | and any other intellectual property rights. It is the responsibility of 11 | all would-be contributors to legally ensure that they indeed have those 12 | rights themselves including, but not limited to, authorization from 13 | their employers to whom they may have given up those rights, knowingly 14 | or otherwise. Any contribution, including those in violation of this 15 | agreement, shall become the legal intellectual property of this project 16 | and its owners. Any violation of this agreement must be resolved between 17 | the contributors and those with whom such disputes exist and shall in no 18 | way involve this project, its owners, maintainers, or any other 19 | contributors who have legally submitted content to this project without 20 | violation. 21 | 22 | ------------------ Developer Certificate of Origin ----------------- 23 | 24 | Developer Certificate of Origin 25 | Version 1.1 26 | 27 | Copyright (C) 2004, 2006 The Linux Foundation and its contributors. 28 | 1 Letterman Drive 29 | Suite D4700 30 | San Francisco, CA, 94129 31 | 32 | Everyone is permitted to copy and distribute verbatim copies of this 33 | license document, but changing it is not allowed. 34 | 35 | Developer's Certificate of Origin 1.1 36 | 37 | By making a contribution to this project, I certify that: 38 | 39 | (a) The contribution was created in whole or in part by me and I 40 | have the right to submit it under the open source license 41 | indicated in the file; or 42 | 43 | (b) The contribution is based upon previous work that, to the best 44 | of my knowledge, is covered under an appropriate open source 45 | license and I have the right under that license to submit that 46 | work with modifications, whether created in whole or in part 47 | by me, under the same open source license (unless I am 48 | permitted to submit under a different license), as indicated 49 | in the file; or 50 | 51 | (c) The contribution was provided directly to me by some other 52 | person who certified (a), (b) or (c) and I have not modified 53 | it. 54 | 55 | (d) I understand and agree that this project and the contribution 56 | are public and that a record of the contribution (including all 57 | personal information I submit with it, including my sign-off) is 58 | maintained indefinitely and may be redistributed consistent with 59 | this project or the open source license(s) involved. 60 | -------------------------------------------------------------------------------- /safer-golangci-lint.yml: -------------------------------------------------------------------------------- 1 | # Copyright © 2021 Montgomery Edwards⁴⁴⁸ (github.com/x448). 2 | # This file is licensed under MIT License. 3 | # 4 | # Safer GitHub Actions Workflow for golangci-lint. 5 | # https://github.com/x448/safer-golangci-lint 6 | # 7 | # safer-golangci-lint.yml 8 | # 9 | # This workflow downloads, verifies, and runs golangci-lint in a 10 | # deterministic, reviewable, and safe manner. 11 | # 12 | # To use: 13 | # Step 1. Copy this file into [your_github_repo]/.github/workflows/ 14 | # Step 2. There's no step 2 if you like the default settings. 15 | # 16 | # See golangci-lint docs for more info at 17 | # https://github.com/golangci/golangci-lint 18 | # 19 | # 100% of the script for downloading, installing, and running golangci-lint 20 | # is embedded in this file. The embedded SHA-256 digest is used to verify the 21 | # downloaded golangci-lint tarball (golangci-lint-1.xx.x-linux-amd64.tar.gz). 22 | # 23 | # The embedded SHA-256 digest matches golangci-lint-1.xx.x-checksums.txt at 24 | # https://github.com/golangci/golangci-lint/releases 25 | # 26 | # To use a newer version of golangci-lint, change these values: 27 | # 1. GOLINTERS_VERSION 28 | # 2. GOLINTERS_TGZ_DGST 29 | # 30 | # Release v1.51.2 (February 19, 2023) 31 | # - Bump golangci-lint to 1.51.2 32 | # - Hash of golangci-lint-1.51.2-linux-amd64.tar.gz 33 | # - SHA-256: 4de479eb9d9bc29da51aec1834e7c255b333723d38dbd56781c68e5dddc6a90b 34 | # This SHA-256 digest matches golangci-lint-1.51.2-checksums.txt at 35 | # https://github.com/golangci/golangci-lint/releases 36 | # 37 | name: linters 38 | 39 | # Remove default permissions and grant only what is required in each job. 40 | permissions: {} 41 | 42 | on: 43 | workflow_dispatch: 44 | pull_request: 45 | types: [opened, synchronize, closed] 46 | push: 47 | branches: [main, master] 48 | 49 | env: 50 | GO_VERSION: 1.19 51 | GOLINTERS_VERSION: 1.51.2 52 | GOLINTERS_ARCH: linux-amd64 53 | GOLINTERS_TGZ_DGST: 4de479eb9d9bc29da51aec1834e7c255b333723d38dbd56781c68e5dddc6a90b 54 | GOLINTERS_TIMEOUT: 15m 55 | OPENSSL_DGST_CMD: openssl dgst -sha256 -r 56 | CURL_CMD: curl --proto =https --tlsv1.2 --location --silent --show-error --fail 57 | 58 | jobs: 59 | main: 60 | name: Lint 61 | runs-on: ubuntu-latest 62 | permissions: 63 | contents: read 64 | steps: 65 | - name: Checkout source 66 | uses: actions/checkout@v3 67 | with: 68 | fetch-depth: 1 69 | 70 | - name: Setup Go 71 | uses: actions/setup-go@v3 72 | with: 73 | go-version: ${{ env.GO_VERSION }} 74 | check-latest: true 75 | 76 | - name: Install golangci-lint 77 | run: | 78 | GOLINTERS_URL_PREFIX="https://github.com/golangci/golangci-lint/releases/download/v${GOLINTERS_VERSION}/" 79 | GOLINTERS_TGZ="golangci-lint-${GOLINTERS_VERSION}-${GOLINTERS_ARCH}.tar.gz" 80 | GOLINTERS_EXPECTED_DGST="${GOLINTERS_TGZ_DGST} *${GOLINTERS_TGZ}" 81 | DGST_CMD="${OPENSSL_DGST_CMD} ${GOLINTERS_TGZ}" 82 | 83 | cd $(mktemp -d /tmp/golinters.XXXXX) 84 | ${CURL_CMD} "${GOLINTERS_URL_PREFIX}${GOLINTERS_TGZ}" --output ${GOLINTERS_TGZ} 85 | 86 | GOLINTERS_GOT_DGST=$(${DGST_CMD}) 87 | if [ "${GOLINTERS_GOT_DGST}" != "${GOLINTERS_EXPECTED_DGST}" ] 88 | then 89 | echo "Digest of tarball is not equal to expected digest." 90 | echo "Expected digest: " "${GOLINTERS_EXPECTED_DGST}" 91 | echo "Got digest: " "${GOLINTERS_GOT_DGST}" 92 | exit 1 93 | fi 94 | 95 | tar --no-same-owner -xzf "${GOLINTERS_TGZ}" --strip-components 1 96 | install golangci-lint $(go env GOPATH)/bin 97 | shell: bash 98 | 99 | # Run required linters enabled in .golangci.yml (or default linters if yml doesn't exist) 100 | - name: Run golangci-lint 101 | run: $(go env GOPATH)/bin/golangci-lint run --timeout="${GOLINTERS_TIMEOUT}" 102 | shell: bash 103 | -------------------------------------------------------------------------------- /internal/secutiry/rsa_util.go: -------------------------------------------------------------------------------- 1 | package security 2 | 3 | import ( 4 | "crypto/rand" 5 | "crypto/rsa" 6 | "crypto/sha256" 7 | "crypto/sha512" 8 | "crypto/x509" 9 | "encoding/base64" 10 | "encoding/pem" 11 | "fmt" 12 | "log" 13 | 14 | "github.com/waldirborbajr/kvstok/internal/must" 15 | ) 16 | 17 | func CheckError(e error) { 18 | if e != nil { 19 | fmt.Printf("%s", e.Error()) 20 | } 21 | } 22 | 23 | // GenerateKeyPair generates a new key pair 24 | func RSA_GenerateKey(bits int) (*rsa.PrivateKey, *rsa.PublicKey) { 25 | privateKey, err := rsa.GenerateKey(rand.Reader, bits) 26 | must.Must(err, "RSA_GenerateKey() - generating key pair.") 27 | return privateKey, &privateKey.PublicKey 28 | } 29 | 30 | // PrivateKeyToBytes private key to bytes 31 | func PrivateKeyToBytes(priv *rsa.PrivateKey) []byte { 32 | privBytes := pem.EncodeToMemory( 33 | &pem.Block{ 34 | Type: "RSA PRIVATE KEY", 35 | Bytes: x509.MarshalPKCS1PrivateKey(priv), 36 | }, 37 | ) 38 | 39 | return privBytes 40 | } 41 | 42 | // PublicKeyToBytes public key to bytes 43 | func PublicKeyToBytes(pub *rsa.PublicKey) []byte { 44 | pubASN1, err := x509.MarshalPKIXPublicKey(pub) 45 | must.Must(err, "PublicKeyToBytes() - converting public key to bytes.") 46 | 47 | pubBytes := pem.EncodeToMemory(&pem.Block{ 48 | Type: "RSA PUBLIC KEY", 49 | Bytes: pubASN1, 50 | }) 51 | 52 | return pubBytes 53 | } 54 | 55 | // BytesToPrivateKey bytes to private key 56 | func BytesToPrivateKey(priv []byte) *rsa.PrivateKey { 57 | block, _ := pem.Decode(priv) 58 | enc := x509.IsEncryptedPEMBlock(block) 59 | b := block.Bytes 60 | var err error 61 | if enc { 62 | log.Println("is encrypted pem block") 63 | b, err = x509.DecryptPEMBlock(block, nil) 64 | must.Must(err, "BytesToPublicKey()[DecryptPEMBlock] - converting private key.") 65 | } 66 | key, err := x509.ParsePKCS1PrivateKey(b) 67 | must.Must(err, "BytesToPrivateKey()[ParsePKCS1PrivateKey] - converting private key") 68 | // if err != nil { 69 | // log.Fatal(err) 70 | // } 71 | return key 72 | } 73 | 74 | // BytesToPublicKey bytes to public key 75 | func BytesToPublicKey(pub []byte) *rsa.PublicKey { 76 | block, _ := pem.Decode(pub) 77 | enc := x509.IsEncryptedPEMBlock(block) 78 | b := block.Bytes 79 | var err error 80 | if enc { 81 | log.Println("is encrypted pem block") 82 | b, err = x509.DecryptPEMBlock(block, nil) 83 | must.Must(err, "BytesToPrivateKey()[IsEncryptedPEMBlock] - converting to public key.") 84 | } 85 | ifc, err := x509.ParsePKIXPublicKey(b) 86 | must.Must(err, "BytesToPublicKey()[ParsePKIXPublicKey] - converting to public key.") 87 | key, ok := ifc.(*rsa.PublicKey) 88 | if !ok { 89 | log.Fatal("not ok") 90 | } 91 | return key 92 | } 93 | 94 | // EncryptWithPublicKey encrypts data with public key 95 | func EncryptWithPublicKey(msg []byte, pub *rsa.PublicKey) []byte { 96 | hash := sha512.New() 97 | ciphertext, err := rsa.EncryptOAEP(hash, rand.Reader, pub, msg, nil) 98 | must.Must(err, "EncryptWithPublicKey() - encrypting with public key.") 99 | return ciphertext 100 | } 101 | 102 | // DecryptWithPrivateKey decrypts data with private key 103 | func DecryptWithPrivateKey(ciphertext []byte, priv *rsa.PrivateKey) []byte { 104 | hash := sha512.New() 105 | plaintext, err := rsa.DecryptOAEP(hash, rand.Reader, priv, ciphertext, nil) 106 | must.Must(err, "DecryptWithPrivateKey() - decrypting with private key.") 107 | return plaintext 108 | } 109 | 110 | func RSA_OAEP_Encrypt(secretMessage string, key rsa.PublicKey) string { 111 | label := []byte("OAEP Encrypted") 112 | rng := rand.Reader 113 | ciphertext, err := rsa.EncryptOAEP(sha256.New(), rng, &key, []byte(secretMessage), label) 114 | CheckError(err) 115 | return base64.StdEncoding.EncodeToString(ciphertext) 116 | } 117 | 118 | func RSA_OAEP_Decrypt(cipherText string, privKey rsa.PrivateKey) string { 119 | ct, _ := base64.StdEncoding.DecodeString(cipherText) 120 | label := []byte("OAEP Encrypted") 121 | rng := rand.Reader 122 | plaintext, err := rsa.DecryptOAEP(sha256.New(), rng, &privKey, ct, label) 123 | CheckError(err) 124 | return string(plaintext) 125 | } 126 | -------------------------------------------------------------------------------- /go.sum: -------------------------------------------------------------------------------- 1 | github.com/antlabs/stl v0.0.2 h1:sna1AXR5yIkNE9lWhCcKbheFJSVfCa3vugnGyakI79s= 2 | github.com/antlabs/stl v0.0.2/go.mod h1:kKrO4xrn9cfS1mJVo+/BqePZjAYMXqD0amGF2Ouq7ac= 3 | github.com/antlabs/timer v0.1.4 h1:MHdE00MDnNfhJCmqSOdLXs35uGNwfkMwfbynxrGmQ1c= 4 | github.com/antlabs/timer v0.1.4/go.mod h1:mpw4zlD5KVjstEyUDp43DGLWsY076Mdo4bS78NTseRE= 5 | github.com/bwmarrin/snowflake v0.3.0 h1:xm67bEhkKh6ij1790JB83OujPR5CzNe8QuQqAgISZN0= 6 | github.com/bwmarrin/snowflake v0.3.0/go.mod h1:NdZxfVWX+oR6y2K0o6qAYv6gIOP9rjG0/E9WsDpxqwE= 7 | github.com/cpuguy83/go-md2man/v2 v2.0.6/go.mod h1:oOW0eioCTA6cOiMLiUPZOpcVxMig6NIQQ7OS05n1F4g= 8 | github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= 9 | github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= 10 | github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= 11 | github.com/gofrs/flock v0.12.1 h1:MTLVXXHf8ekldpJk3AKicLij9MdwOWkZ+a/jHHZby9E= 12 | github.com/gofrs/flock v0.12.1/go.mod h1:9zxTsyu5xtJ9DK+1tFZyibEV7y3uwDxPPfbxeeHCoD0= 13 | github.com/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2s0bqwp9tc8= 14 | github.com/inconshreveable/mousetrap v1.1.0/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw= 15 | github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE= 16 | github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk= 17 | github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= 18 | github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= 19 | github.com/nutsdb/nutsdb v1.0.4 h1:BurzkxijXJY1/AkIXe1ek+U1ta3WGi6nJt4nCLqkxQ8= 20 | github.com/nutsdb/nutsdb v1.0.4/go.mod h1:jIbbpBXajzTMZ0o33Yn5zoYIo3v0Dz4WstkVce+sYuQ= 21 | github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= 22 | github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= 23 | github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= 24 | github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= 25 | github.com/rogpeppe/go-internal v1.13.1 h1:KvO1DLK/DRN07sQ1LQKScxyZJuNnedQ5/wKSR38lUII= 26 | github.com/rogpeppe/go-internal v1.13.1/go.mod h1:uMEvuHeurkdAXX61udpOXGD/AzZDWNMNyH2VO9fmH0o= 27 | github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= 28 | github.com/spf13/cobra v1.10.1 h1:lJeBwCfmrnXthfAupyUTzJ/J4Nc1RsHC/mSRU2dll/s= 29 | github.com/spf13/cobra v1.10.1/go.mod h1:7SmJGaTHFVBY0jW4NXGluQoLvhqFQM+6XSKD+P4XaB0= 30 | github.com/spf13/pflag v1.0.9 h1:9exaQaMOCwffKiiiYk6/BndUBv+iRViNW+4lEMi0PvY= 31 | github.com/spf13/pflag v1.0.9/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= 32 | github.com/stretchr/testify v1.10.0 h1:Xv5erBjTwe/5IxqUQTdXv5kgmIvbHo3QQyRwhJsOfJA= 33 | github.com/stretchr/testify v1.10.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= 34 | github.com/tidwall/btree v1.7.0 h1:L1fkJH/AuEh5zBnnBbmTwQ5Lt+bRJ5A8EWecslvo9iI= 35 | github.com/tidwall/btree v1.7.0/go.mod h1:twD9XRA5jj9VUQGELzDO4HPQTNJsoWWfYEL+EUQ2cKY= 36 | github.com/xujiajun/mmap-go v1.0.1 h1:7Se7ss1fLPPRW+ePgqGpCkfGIZzJV6JPq9Wq9iv/WHc= 37 | github.com/xujiajun/mmap-go v1.0.1/go.mod h1:CNN6Sw4SL69Sui00p0zEzcZKbt+5HtEnYUsc6BKKRMg= 38 | github.com/xujiajun/utils v0.0.0-20220904132955-5f7c5b914235 h1:w0si+uee0iAaCJO9q86T6yrhdadgcsoNuh47LrUykzg= 39 | github.com/xujiajun/utils v0.0.0-20220904132955-5f7c5b914235/go.mod h1:MR4+0R6A9NS5IABnIM3384FfOq8QFVnm7WDrBOhIaMU= 40 | golang.org/x/sys v0.0.0-20181221143128-b4a75ba826a6/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= 41 | golang.org/x/sys v0.25.0 h1:r+8e+loiHxRqhXVl6ML1nO3l1+oFoWbnlu2Ehimmi34= 42 | golang.org/x/sys v0.25.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= 43 | gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= 44 | gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk= 45 | gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q= 46 | gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= 47 | gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= 48 | -------------------------------------------------------------------------------- /CODE_OF_CONDUCT.md: -------------------------------------------------------------------------------- 1 | # Contributor Covenant Code of Conduct 2 | 3 | ## Our Pledge 4 | 5 | We as members, contributors, and leaders pledge to make participation in our 6 | community a harassment-free experience for everyone, regardless of age, body 7 | size, visible or invisible disability, ethnicity, sex characteristics, gender 8 | identity and expression, level of experience, education, socio-economic status, 9 | nationality, personal appearance, race, religion, or sexual identity 10 | and orientation. 11 | 12 | We pledge to act and interact in ways that contribute to an open, welcoming, 13 | diverse, inclusive, and healthy community. 14 | 15 | ## Our Standards 16 | 17 | Examples of behavior that contributes to a positive environment for our 18 | community include: 19 | 20 | * Demonstrating empathy and kindness toward other people 21 | * Being respectful of differing opinions, viewpoints, and experiences 22 | * Giving and gracefully accepting constructive feedback 23 | * Accepting responsibility and apologizing to those affected by our mistakes, 24 | and learning from the experience 25 | * Focusing on what is best not just for us as individuals, but for the 26 | overall community 27 | 28 | Examples of unacceptable behavior include: 29 | 30 | * The use of sexualized language or imagery, and sexual attention or 31 | advances of any kind 32 | * Trolling, insulting or derogatory comments, and personal or political attacks 33 | * Public or private harassment 34 | * Publishing others' private information, such as a physical or email 35 | address, without their explicit permission 36 | * Other conduct which could reasonably be considered inappropriate in a 37 | professional setting 38 | 39 | ## Enforcement Responsibilities 40 | 41 | Community leaders are responsible for clarifying and enforcing our standards of 42 | acceptable behavior and will take appropriate and fair corrective action in 43 | response to any behavior that they deem inappropriate, threatening, offensive, 44 | or harmful. 45 | 46 | Community leaders have the right and responsibility to remove, edit, or reject 47 | comments, commits, code, wiki edits, issues, and other contributions that are 48 | not aligned to this Code of Conduct, and will communicate reasons for moderation 49 | decisions when appropriate. 50 | 51 | ## Scope 52 | 53 | This Code of Conduct applies within all community spaces, and also applies when 54 | an individual is officially representing the community in public spaces. 55 | Examples of representing our community include using an official e-mail address, 56 | posting via an official social media account, or acting as an appointed 57 | representative at an online or offline event. 58 | 59 | ## Enforcement 60 | 61 | Instances of abusive, harassing, or otherwise unacceptable behavior may be 62 | reported to the community leaders responsible for enforcement at 63 | . 64 | All complaints will be reviewed and investigated promptly and fairly. 65 | 66 | All community leaders are obligated to respect the privacy and security of the 67 | reporter of any incident. 68 | 69 | ## Enforcement Guidelines 70 | 71 | Community leaders will follow these Community Impact Guidelines in determining 72 | the consequences for any action they deem in violation of this Code of Conduct: 73 | 74 | ### 1. Correction 75 | 76 | **Community Impact**: Use of inappropriate language or other behavior deemed 77 | unprofessional or unwelcome in the community. 78 | 79 | **Consequence**: A private, written warning from community leaders, providing 80 | clarity around the nature of the violation and an explanation of why the 81 | behavior was inappropriate. A public apology may be requested. 82 | 83 | ### 2. Warning 84 | 85 | **Community Impact**: A violation through a single incident or series 86 | of actions. 87 | 88 | **Consequence**: A warning with consequences for continued behavior. No 89 | interaction with the people involved, including unsolicited interaction with 90 | those enforcing the Code of Conduct, for a specified period of time. This 91 | includes avoiding interactions in community spaces as well as external channels 92 | like social media. Violating these terms may lead to a temporary or 93 | permanent ban. 94 | 95 | ### 3. Temporary Ban 96 | 97 | **Community Impact**: A serious violation of community standards, including 98 | sustained inappropriate behavior. 99 | 100 | **Consequence**: A temporary ban from any sort of interaction or public 101 | communication with the community for a specified period of time. No public or 102 | private interaction with the people involved, including unsolicited interaction 103 | with those enforcing the Code of Conduct, is allowed during this period. 104 | Violating these terms may lead to a permanent ban. 105 | 106 | ### 4. Permanent Ban 107 | 108 | **Community Impact**: Demonstrating a pattern of violation of community 109 | standards, including sustained inappropriate behavior, harassment of an 110 | individual, or aggression toward or disparagement of classes of individuals. 111 | 112 | **Consequence**: A permanent ban from any sort of public interaction within 113 | the community. 114 | 115 | ## Attribution 116 | 117 | This Code of Conduct is adapted from the [Contributor Covenant][homepage], 118 | version 2.0, available at 119 | https://www.contributor-covenant.org/version/2/0/code_of_conduct.html. 120 | 121 | Community Impact Guidelines were inspired by [Mozilla's code of conduct 122 | enforcement ladder](https://github.com/mozilla/diversity). 123 | 124 | [homepage]: https://www.contributor-covenant.org 125 | 126 | For answers to common questions about this code of conduct, see the FAQ at 127 | https://www.contributor-covenant.org/faq. Translations are available at 128 | https://www.contributor-covenant.org/translations. 129 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ## KVStok 2 | 3 | [](https://github.com/waldirborbajr/kvstok/actions/workflows/typo-check.yaml) 4 | [](https://github.com/waldirborbajr/kvstok/actions/workflows/build-test.yaml) 5 | [](https://github.com/waldirborbajr/kvstok/actions/workflows/goreleaser.yaml) 6 | 7 |
8 |
9 |