├── 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 | [![Typo Check](https://github.com/waldirborbajr/kvstok/actions/workflows/typo-check.yaml/badge.svg)](https://github.com/waldirborbajr/kvstok/actions/workflows/typo-check.yaml) 4 | [![Build & Test](https://github.com/waldirborbajr/kvstok/actions/workflows/build-test.yaml/badge.svg)](https://github.com/waldirborbajr/kvstok/actions/workflows/build-test.yaml) 5 | [![Build & Release](https://github.com/waldirborbajr/kvstok/actions/workflows/goreleaser.yaml/badge.svg)](https://github.com/waldirborbajr/kvstok/actions/workflows/goreleaser.yaml) 6 | 7 |

8 | 9 |

10 | 11 | `tl;dr:` KVStoK is an open-source software built-in with the main aim of being a personal [KEY][VALUE] store, to keep system variables as parameters or passwords or anything else stored in a single place. 12 | 13 | With KVStoK you do not need to export a variable to use in your terminal routines and you can open a lot of terminals and you will always keep the content available to use. 14 | 15 | Is KVStoK good for DevOps? Yes, if you work with DevOps and have to manage a lot of credentials, KVStoK is up to you. 16 | 17 | I am a streamer (twitch, youtube, online class, etc.), is KVStoK ready for me? Yes, online producer, KVStoK it is up to you because you do not need anymore hide or blur your screen to type any sensible data. 18 | 19 | Can I manage my credentials remotely from the cloud? No, unfortunately, KVStoK, for security reasons is not available to manage or store credentials on the cloud. In the soon future will be possible to manage all credentials in a single place with security and performance. 20 | 21 | ### How to use 22 | 23 | #### Typing `full` command name 24 | 25 | ```sh 26 | 27 | # Store a value 28 | $ kvstok addkv containerpwd 123SecretPWD 29 | 30 | # List all stored values if informed json will generate a json file 31 | $ kvstok lstkv 32 | key_sample1 mysecret 33 | key_sample2 anothersecret 34 | key_sample3 moresecret 35 | 36 | # Grab a value stored into a key 37 | $ kvstok getkv containerpwd 38 | 123SecretPWD 39 | 40 | # Remove a stored key/value from database storage 41 | $ kvstok delkv containerpwd 42 | 43 | # Unicode params are allowed too 44 | $ kvstok addkv someParam 喵 45 | $ kvstok getkv someParam 46 | 喵 47 | 48 | # Adding a temporarily key TTL of 10 minutes 49 | # After TTL the key will be automatically removed 50 | $ kvstok ttladdkv mytempkey mytempvalue 10 51 | ``` 52 | 53 | ### Integrated to shell script 54 | 55 | ```sh 56 | #!/bin/bash 57 | 58 | dosomething = $(kvstok getkv someParam) 59 | echo ${dosomething} 60 | .. 61 | . 62 | ``` 63 | 64 | #### Typing `alias` of command name, first letter 65 | 66 | ```sh 67 | 68 | # Store a value 69 | $ kvstok a containerpwd 123SecretPWD 70 | 71 | # List all stored values if informed json will generate a json file 72 | $ kvstok l 73 | key_sample1 mysecret 74 | key_sample2 anothersecret 75 | key_sample3 moresecret 76 | 77 | # Grab a value stored into a key 78 | $ kvstok g containerpwd 79 | 123SecretPWD 80 | 81 | # Remove a stored key/value from database storage 82 | $ kvstok d containerpwd 83 | 84 | # Unicode params are allowed too 85 | $ kvstok a someParam 喵 86 | $ kvstok g someParam 87 | 喵 88 | 89 | # Adding a temporarily key TTL of 10 minutes 90 | # After TTL the key will be automatically removed 91 | $ kvstok t mytempkey mytempvalue 10 92 | ``` 93 | 94 | ### Integrated to shell script 95 | 96 | ```sh 97 | #!/bin/bash 98 | 99 | dosomething = $(kvstok g someParam) 100 | echo ${dosomething} 101 | .. 102 | . 103 | ``` 104 | 105 | ### More examples of use 106 | 107 | ```sh 108 | curl -v -u $(kvstok getkv user):$(kvstok getkv token) https://ghcr.io/v2/ 109 | ``` 110 | 111 | ### Install 112 | 113 | ### Download binary according to you OS version at 114 | 115 | #### macOS 116 | 117 | 1. Download **kvstok_x.x.x_darwin_XXXX.tar.gz** 118 | 2. Extract: `tar xzvf kvstok_x.x.x_darwin_XXXX.tar.gz` 119 | 3. Move to `mv kvstok ~/bin` 120 | 4. Make sure that `$HOME/bin` it is in your library path. 121 | 5. Run `kvstok` 122 | 123 | #### Linux 124 | 125 | 1. Download **kvstok_x.x.x_linux_XXXX.tar.gz** 126 | 2. Extract: `tar xzvf kvstok_x.x.x_linux_XXXX.tar.gz` 127 | 3. Move to `mv kvstok ~/bin` 128 | 4. Make sure that `$HOME/bin` it is in your library path. 129 | 5. Run `kvstok` 130 | 131 | ## How can I contribute? 132 | 133 | Kindly refer to [CONTRIBUTING.md](./CONTRIBUTING.md) file to learn how to contribute! 134 | 135 | And that's it! 136 | Follow these steps to make your very first pull request. 137 | 138 | ## License 139 | 140 | [Apache](https://github.com/WaldirBorbaJR/kvstok/-/blob/main/LICENSE) 141 | 142 | ## Legal 143 | 144 | Copyright 2022-2023 Waldir Borba Junior () 145 | SPDX-License-Identifier: Apache-2.0 146 | 147 | ## TODO 148 | 149 | **Note: This file is no longer being updated.** 150 | 151 | The todo file does not represent ALL of the missing features. This file just shows the features which I noticed were missing and I have to implement. 152 | 153 | For a list of all closed TODO: `is:issue is:closed TODO` 154 | 155 | For a list of all open TODO: `is:issue is:open TODO` 156 | 157 | ## Technology 158 | 159 | | logo | gopher | nutsdb | cobra | 160 | 161 | [KVStoK]|[GO](https://go.dev/)|[NutsDB](https://github.com/nutsdb/nutsdb)|[Cobra](https://cobra.dev/)| 162 | 163 | ## Star History 164 | 165 | [![Star History Chart](https://api.star-history.com/svg?repos=waldirborbajr/kvstok&type=Date)](https://star-history.com/#waldirborbajr/kvstok&Date) 166 | -------------------------------------------------------------------------------- /run: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | # 3 | # v0.3.2 4 | 5 | set -e 6 | set -o errexit 7 | set -o nounset 8 | set -o pipefail 9 | # set -o xtrace # for debug proupose 10 | # 11 | ############################################################# 12 | # Parsing arguments 13 | ############################################################# 14 | # 15 | arg0="${0:-}" 16 | arg1="${1:-}" 17 | arg2="${2:-}" 18 | arg3="${3:-}" 19 | # 20 | ############################################################# 21 | # Application Name & Docker Hub Configuration Section 22 | ############################################################# 23 | # 24 | # APP_NAME contains it is formed by [hub registry / application name : tag] 25 | __APP_NAME="kvstok" 26 | # for docker registry fill information below 27 | __HUB_REGISTRY="waldirborbajr" 28 | __TAG_LABEL=":latest" 29 | # 30 | ############################################################# 31 | # Constants Section 32 | ############################################################# 33 | # 34 | # foreground colors 35 | __RED=$(tput setaf 1) 36 | __GREEN=$(tput setaf 2) 37 | __YELLOW=$(tput setaf 3) 38 | __BLUE=$(tput setaf 4) 39 | __MAGENTA=$(tput setaf 5) 40 | __CYAN=$(tput setaf 6) 41 | __WHITE=$(tput setaf 7) 42 | # 43 | # Set magic variables for current file & dir 44 | __dir="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" 45 | __file="${__dir}/$(basename "${BASH_SOURCE[0]}")" 46 | __base="$(basename ${__file} .sh)" 47 | __root="$(cd "$(dirname "${__dir}")" && pwd)" # <-- change this as it depends on your app 48 | # 49 | __DOCKER=${__HUB_REGISTRY}+"/"+${__APP_NAME}+":"+${__TAG_LABEL} 50 | # 51 | __BUILD_START="starting build for" 52 | __BUILD_DONE="${__GREEN}.. build [ok] .. ${__WHITE}" 53 | __BUILD_FAIL="${__RED}.. build [fail] .. ${__WHITE}" 54 | # 55 | ############################################################# 56 | # Certificate Functions 57 | ############################################################# 58 | # 59 | function gen:cert { 60 | openssl req \ 61 | -x510 \ 62 | -newkey rsa:4097 \ 63 | -keyout ${__APP_NAME}-private.key \ 64 | -out ${__APP_NAME}.pem \ 65 | -days 366 \ 66 | -subj "/C=BR/ST=Paraná/L=Curitiba/O=Pessoal/OU=TI/CN=Desenvolvimento" \ 67 | -nodes 68 | } 69 | # 70 | ############################################################# 71 | # Stress Test Functions 72 | ############################################################# 73 | # 74 | function wrk:request { 75 | if [[ -z "${arg2}" ]]; then 76 | echo -e "Usage:" 77 | echo -e " run ${arg1} host+port+path" 78 | echo -e "" 79 | echo -e "Example:" 80 | echo -e " run ${arg1} 127.0.0.1:1010/ping" 81 | echo -e "" 82 | exit -1 83 | fi 84 | 85 | # warmup 86 | reset 87 | echo -e "\n${__RED} warmup of 3s ${__WHITE}\n" 88 | env wrk -t 6 -c 1000 -d 3s http://${arg2} 89 | echo -e "\n${__RED} collecting data 6 threads for 60s ${__WHITE}\n" 90 | # let's go 91 | env wrk -t 6 -c 1000 -d 60s http://${arg2} 92 | echo -e "${__GREEN} [done] ${__WHITE}" 93 | } 94 | 95 | function wrk:latency { 96 | if [[ -z ${arg2} ]]; then 97 | echo -e "Usage:" 98 | echo -e " run ${arg1} host+port+path" 99 | echo -e "" 100 | echo -e "Example:" 101 | echo -e " run ${arg1} 127.0.0.1:1010/ping" 102 | echo -e "" 103 | exit -1 104 | fi 105 | 106 | # warmup 107 | reset 108 | echo -e "\n${__RED} warmup of 3s ${__WHITE}\n" 109 | env wrk --latency -t 6 -c 1000 -d 3s http://${arg2} 110 | echo -e "\n${__RED} collecting data 6 threads for 60s ${__WHITE}\n" 111 | # let's go 112 | env wrk --latency -t 6 -c 1000 -d 60s http://${arg2} 113 | echo -e "${__GREEN} [done] ${__WHITE}" 114 | } 115 | # 116 | ############################################################# 117 | # Podman / Docker Functions 118 | ############################################################# 119 | # 120 | function pod:deploy { 121 | echo -e "${__GREEN} -[ Clean images ]- ${__WHITE}" 122 | podman rmi $(podman images | grep "" | awk '{print $4}') --force 123 | echo -e "${__BLUE} [ pull ] ${__WHITE}" 124 | podman pull waldirborbajr/techbot:latest 125 | 126 | podman-compose stop ${__DOCKER} 127 | podman-compose rm --force ${__DOCKER} 128 | podman-compose up -d ${__DOCKER} 129 | podman-compose ps 130 | echo -e "${__YELLOW}Generated Run podman-compose ${__WHITE}\n" 131 | } 132 | 133 | function pod:run { 134 | # podman run --rm -it "${2:-}" "${2:-}" 135 | podman run --detach --rm --name ${__DOCKER} --publish 9091:9090 ${__DOCKER} 136 | } 137 | 138 | function pod:kill { 139 | podman kill ${__DOCKER} 140 | } 141 | 142 | function pod:validate { 143 | if [[ -z ${arg2} ]]; then 144 | echo -e "Usage:" 145 | echo -e " run ${arg1} host+port" 146 | echo -e "" 147 | echo -e "Example:" 148 | echo -e " run ${arg1} 127.0.0.1:1010" 149 | echo -e "" 150 | exit -1 151 | fi 152 | 153 | curl -v ${arg2} 154 | } 155 | 156 | function pod:build { 157 | echo -e "${__BLUE} starting... ${__WHITE}" 158 | podman build -f ./podman/podmanfile -t ${__DOCKER} . 159 | echo -e "${__GREEN} [done] ${__WHITE}" 160 | } 161 | 162 | function pod:prune { 163 | echo -e "${__BLUE} starting... ${__WHITE}" 164 | podman system prune -af --volumes 165 | podman ps -a -q | xargs podman rm 166 | podman images -a -q | xargs podman rmi -fa 167 | echo -e "${__GREEN} [done] ${__WHITE}" 168 | } 169 | 170 | function pod:dang { 171 | echo -e "${__BLUE} starting... ${__WHITE}" 172 | podman rmi -f $(podman images -q -f dangling=true) 173 | echo -e "${__GREEN} [done] ${__WHITE}" 174 | } 175 | 176 | function pod:remove { 177 | echo -e "${__BLUE} starting... ${__WHITE}" 178 | podman rmi -f $(podman ps -a -q) 179 | echo -e "${__GREEN} [done] ${__WHITE}" 180 | } 181 | 182 | function podcompose:ps { 183 | podman-compose ps 184 | } 185 | # 186 | ############################################################# 187 | # Build Functions 188 | ############################################################# 189 | # 190 | function build:windows { 191 | echo -e "${__BLUE} .:: ${__BUILD_START} Windows ::. ${__WHITE}" 192 | 193 | CGO_ENABLED=1 GOARCH=amd64 GOOS=windows go build -a -installsuffix cgo -ldflags '-s -w -extldflags "-static"' -trimpath -o ./bin/windows/${__APP_NAME}.exe cmd/main.go 194 | 195 | status=$? 196 | if test $status -eq 0 197 | then 198 | echo -e "${__BUILD_DONE} " 199 | else 200 | echo -e "${__BUILD_FAIL} " 201 | fi 202 | } 203 | 204 | function build:macos { 205 | echo -e "${__BLUE} .:: ${__BUILD_START} MacOS ::. ${__WHITE}" 206 | 207 | CGO_ENABLED=0 GOARCH=amd64 GOOS=darwin go build -a -installsuffix cgo -ldflags '-s -w -extldflags "-static"' -trimpath -o ./bin/macos/${__APP_NAME} cmd/cli/main.go 208 | 209 | status=$? 210 | if test $status -eq 0 211 | then 212 | echo -e "${__BUILD_DONE} " 213 | else 214 | echo -e "${__BUILD_FAIL} " 215 | fi 216 | } 217 | 218 | function build:raspi { 219 | echo -e "${__BLUE} .:: ${__BUILD_START} RaspiberryPi 3/4 ::. ${__WHITE}" 220 | 221 | CGO_ENABLED=0 GOARCH=arm GOARM=7 GOOS=linux go build -a -installsuffix cgo -ldflags '-s -w -extldflags "-static"' -trimpath -o ./bin/raspi/${__APP_NAME} cmd/main.go 222 | 223 | status=$? 224 | if test $status -eq 0 225 | then 226 | echo -e "${__BUILD_DONE} " 227 | else 228 | echo -e "${__BUILD_FAIL} " 229 | fi 230 | } 231 | 232 | function build:linux { 233 | echo -e "${__BLUE} .:: ${__BUILD_START} Linux ::. ${__WHITE}" 234 | 235 | CGO_ENABLED=0 GOARCH=amd64 GOOS=linux go build -a -installsuffix cgo -ldflags '-s -w -extldflags "-static"' -trimpath -o ./bin/linux/${__APP_NAME} cmd/cli/main.go 236 | 237 | status=$? 238 | if test $status -eq 0 239 | then 240 | echo -e "${__BUILD_DONE} " 241 | else 242 | echo -e "${__BUILD_FAIL} " 243 | fi 244 | } 245 | # 246 | ################################################################################ 247 | # Install / Uninstall Functions 248 | ################################################################################ 249 | # 250 | function make:uninstall { 251 | target=$(uname -s) 252 | 253 | case ${target} in 254 | Linux*) sudo rm -rf /usr/local/bin/${__APP_NAME};; 255 | Darwin*) sudo rm -rf /usr/local/bin/${__APP_NAME};; 256 | esac 257 | } 258 | 259 | function make:install { 260 | clear 261 | 262 | target=$(uname -s) 263 | 264 | echo -e "${__BLUE}Installing KVStoK for" ${__YELLOW} ${target} ${__WHITE} 265 | 266 | case ${target} in 267 | Linux*) cp bin/linux/${__APP_NAME} ~/.local/bin/;; 268 | Darwin*) cp bin/macos/${__APP_NAME} ~/.local/bin/;; 269 | esac 270 | 271 | echo -e "${__GREEN} [done] ${__WHITE}" 272 | 273 | } 274 | 275 | function make:clean { 276 | rm -rf bin/ 277 | } 278 | # 279 | ################################################################################ 280 | # Git Version Functions 281 | ################################################################################ 282 | # 283 | # 284 | ################################################################################ 285 | # Help Functions 286 | ################################################################################ 287 | # 288 | function help { 289 | printf "%s [args]\n\nTasks:\n" "${0}" 290 | 291 | compgen -A function | grep -v "^_" | cat -n 292 | 293 | printf "\nExtended help:\n Each task has comments for general usage\n" 294 | } 295 | # 296 | ################################################################################ 297 | # Timestamp on finish 298 | ################################################################################ 299 | # 300 | # This idea is heavily inspired by: https://github.com/adriancooney/Taskfile 301 | TIMEFORMAT=$'\nTask completed in %3lR' 302 | time "${@:-help}" 303 | 304 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Apache License 2 | Version 2.0, January 2004 3 | http://www.apache.org/licenses/ 4 | 5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 6 | 7 | 1. Definitions. 8 | 9 | "License" shall mean the terms and conditions for use, reproduction, 10 | and distribution as defined by Sections 1 through 9 of this document. 11 | 12 | "Licensor" shall mean the copyright owner or entity authorized by 13 | the copyright owner that is granting the License. 14 | 15 | "Legal Entity" shall mean the union of the acting entity and all 16 | other entities that control, are controlled by, or are under common 17 | control with that entity. For the purposes of this definition, 18 | "control" means (i) the power, direct or indirect, to cause the 19 | direction or management of such entity, whether by contract or 20 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 21 | outstanding shares, or (iii) beneficial ownership of such entity. 22 | 23 | "You" (or "Your") shall mean an individual or Legal Entity 24 | exercising permissions granted by this License. 25 | 26 | "Source" form shall mean the preferred form for making modifications, 27 | including but not limited to software source code, documentation 28 | source, and configuration files. 29 | 30 | "Object" form shall mean any form resulting from mechanical 31 | transformation or translation of a Source form, including but 32 | not limited to compiled object code, generated documentation, 33 | and conversions to other media types. 34 | 35 | "Work" shall mean the work of authorship, whether in Source or 36 | Object form, made available under the License, as indicated by a 37 | copyright notice that is included in or attached to the work 38 | (an example is provided in the Appendix below). 39 | 40 | "Derivative Works" shall mean any work, whether in Source or Object 41 | form, that is based on (or derived from) the Work and for which the 42 | editorial revisions, annotations, elaborations, or other modifications 43 | represent, as a whole, an original work of authorship. For the purposes 44 | of this License, Derivative Works shall not include works that remain 45 | separable from, or merely link (or bind by name) to the interfaces of, 46 | the Work and Derivative Works thereof. 47 | 48 | "Contribution" shall mean any work of authorship, including 49 | the original version of the Work and any modifications or additions 50 | to that Work or Derivative Works thereof, that is intentionally 51 | submitted to Licensor for inclusion in the Work by the copyright owner 52 | or by an individual or Legal Entity authorized to submit on behalf of 53 | the copyright owner. For the purposes of this definition, "submitted" 54 | means any form of electronic, verbal, or written communication sent 55 | to the Licensor or its representatives, including but not limited to 56 | communication on electronic mailing lists, source code control systems, 57 | and issue tracking systems that are managed by, or on behalf of, the 58 | Licensor for the purpose of discussing and improving the Work, but 59 | excluding communication that is conspicuously marked or otherwise 60 | designated in writing by the copyright owner as "Not a Contribution." 61 | 62 | "Contributor" shall mean Licensor and any individual or Legal Entity 63 | on behalf of whom a Contribution has been received by Licensor and 64 | subsequently incorporated within the Work. 65 | 66 | 2. Grant of Copyright License. Subject to the terms and conditions of 67 | this License, each Contributor hereby grants to You a perpetual, 68 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 69 | copyright license to reproduce, prepare Derivative Works of, 70 | publicly display, publicly perform, sublicense, and distribute the 71 | Work and such Derivative Works in Source or Object form. 72 | 73 | 3. Grant of Patent License. Subject to the terms and conditions of 74 | this License, each Contributor hereby grants to You a perpetual, 75 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 76 | (except as stated in this section) patent license to make, have made, 77 | use, offer to sell, sell, import, and otherwise transfer the Work, 78 | where such license applies only to those patent claims licensable 79 | by such Contributor that are necessarily infringed by their 80 | Contribution(s) alone or by combination of their Contribution(s) 81 | with the Work to which such Contribution(s) was submitted. If You 82 | institute patent litigation against any entity (including a 83 | cross-claim or counterclaim in a lawsuit) alleging that the Work 84 | or a Contribution incorporated within the Work constitutes direct 85 | or contributory patent infringement, then any patent licenses 86 | granted to You under this License for that Work shall terminate 87 | as of the date such litigation is filed. 88 | 89 | 4. Redistribution. You may reproduce and distribute copies of the 90 | Work or Derivative Works thereof in any medium, with or without 91 | modifications, and in Source or Object form, provided that You 92 | meet the following conditions: 93 | 94 | (a) You must give any other recipients of the Work or 95 | Derivative Works a copy of this License; and 96 | 97 | (b) You must cause any modified files to carry prominent notices 98 | stating that You changed the files; and 99 | 100 | (c) You must retain, in the Source form of any Derivative Works 101 | that You distribute, all copyright, patent, trademark, and 102 | attribution notices from the Source form of the Work, 103 | excluding those notices that do not pertain to any part of 104 | the Derivative Works; and 105 | 106 | (d) If the Work includes a "NOTICE" text file as part of its 107 | distribution, then any Derivative Works that You distribute must 108 | include a readable copy of the attribution notices contained 109 | within such NOTICE file, excluding those notices that do not 110 | pertain to any part of the Derivative Works, in at least one 111 | of the following places: within a NOTICE text file distributed 112 | as part of the Derivative Works; within the Source form or 113 | documentation, if provided along with the Derivative Works; or, 114 | within a display generated by the Derivative Works, if and 115 | wherever such third-party notices normally appear. The contents 116 | of the NOTICE file are for informational purposes only and 117 | do not modify the License. You may add Your own attribution 118 | notices within Derivative Works that You distribute, alongside 119 | or as an addendum to the NOTICE text from the Work, provided 120 | that such additional attribution notices cannot be construed 121 | as modifying the License. 122 | 123 | You may add Your own copyright statement to Your modifications and 124 | may provide additional or different license terms and conditions 125 | for use, reproduction, or distribution of Your modifications, or 126 | for any such Derivative Works as a whole, provided Your use, 127 | reproduction, and distribution of the Work otherwise complies with 128 | the conditions stated in this License. 129 | 130 | 5. Submission of Contributions. Unless You explicitly state otherwise, 131 | any Contribution intentionally submitted for inclusion in the Work 132 | by You to the Licensor shall be under the terms and conditions of 133 | this License, without any additional terms or conditions. 134 | Notwithstanding the above, nothing herein shall supersede or modify 135 | the terms of any separate license agreement you may have executed 136 | with Licensor regarding such Contributions. 137 | 138 | 6. Trademarks. This License does not grant permission to use the trade 139 | names, trademarks, service marks, or product names of the Licensor, 140 | except as required for reasonable and customary use in describing the 141 | origin of the Work and reproducing the content of the NOTICE file. 142 | 143 | 7. Disclaimer of Warranty. Unless required by applicable law or 144 | agreed to in writing, Licensor provides the Work (and each 145 | Contributor provides its Contributions) on an "AS IS" BASIS, 146 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 147 | implied, including, without limitation, any warranties or conditions 148 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 149 | PARTICULAR PURPOSE. You are solely responsible for determining the 150 | appropriateness of using or redistributing the Work and assume any 151 | risks associated with Your exercise of permissions under this License. 152 | 153 | 8. Limitation of Liability. In no event and under no legal theory, 154 | whether in tort (including negligence), contract, or otherwise, 155 | unless required by applicable law (such as deliberate and grossly 156 | negligent acts) or agreed to in writing, shall any Contributor be 157 | liable to You for damages, including any direct, indirect, special, 158 | incidental, or consequential damages of any character arising as a 159 | result of this License or out of the use or inability to use the 160 | Work (including but not limited to damages for loss of goodwill, 161 | work stoppage, computer failure or malfunction, or any and all 162 | other commercial damages or losses), even if such Contributor 163 | has been advised of the possibility of such damages. 164 | 165 | 9. Accepting Warranty or Additional Liability. While redistributing 166 | the Work or Derivative Works thereof, You may choose to offer, 167 | and charge a fee for, acceptance of support, warranty, indemnity, 168 | or other liability obligations and/or rights consistent with this 169 | License. However, in accepting such obligations, You may act only 170 | on Your own behalf and on Your sole responsibility, not on behalf 171 | of any other Contributor, and only if You agree to indemnify, 172 | defend, and hold each Contributor harmless for any liability 173 | incurred by, or claims asserted against, such Contributor by reason 174 | of your accepting any such warranty or additional liability. 175 | 176 | END OF TERMS AND CONDITIONS 177 | 178 | APPENDIX: How to apply the Apache License to your work. 179 | 180 | To apply the Apache License to your work, attach the following 181 | boilerplate notice, with the fields enclosed by brackets "[]" 182 | replaced with your own identifying information. (Don't include 183 | the brackets!) The text should be enclosed in the appropriate 184 | comment syntax for the file format. We also recommend that a 185 | file or class name and description of purpose be included on the 186 | same "printed page" as the copyright notice for easier 187 | identification within third-party archives. 188 | 189 | Copyright 2022 Waldir Borba Junior 190 | 191 | Licensed under the Apache License, Version 2.0 (the "License"); 192 | you may not use this file except in compliance with the License. 193 | You may obtain a copy of the License at 194 | 195 | http://www.apache.org/licenses/LICENSE-2.0 196 | 197 | Unless required by applicable law or agreed to in writing, software 198 | distributed under the License is distributed on an "AS IS" BASIS, 199 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 200 | See the License for the specific language governing permissions and 201 | limitations under the License. 202 | 203 | --------------------------------------------------------------------------------