Skip to content
This repository has been archived by the owner on Jun 23, 2024. It is now read-only.

Commit

Permalink
Merge pull request #12 from yousefvand/cli
Browse files Browse the repository at this point in the history
Cli
  • Loading branch information
yousefvand authored Sep 27, 2021
2 parents d9e4b0b + 877e378 commit d24fe48
Show file tree
Hide file tree
Showing 45 changed files with 1,391 additions and 421 deletions.
47 changes: 25 additions & 22 deletions .vscode/settings.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,53 +2,56 @@
"cSpell.words": [
"Aamoo",
"Archlinux",
"chmod",
"dbus",
"Debugf",
"dhkx",
"Diffie",
"Errorf",
"fips",
"freedesktop",
"godbus",
"Gopkg",
"HKDF",
"HMAC",
"Hötzel",
"Infof",
"MASTERPASSWORD",
"PKCS",
"PKGBUID",
"PKGBUILD",
"READWRITE",
"Ramiz",
"Remisa",
"Remmina",
"SIGHUP",
"Struct",
"Tracef",
"Unpadded",
"Warnf",
"Warningf",
"Yousefvand",
"chmod",
"dbus",
"dhkx",
"fips",
"freedesktop",
"godbus",
"Jürgen",
"keyrings",
"killall",
"MASTERPASSWORD",
"monnand",
"namcap",
"oayays",
"pacman",
"PKCS",
"PKGBUID",
"PKGBUILD",
"pkgver",
"Ramiz",
"READWRITE",
"Remisa",
"Remmina",
"scrouthtv",
"secretservice",
"secretserviced",
"SIGHUP",
"somepassword",
"stretchr",
"Struct",
"structs",
"Tracef",
"unalias",
"unencrypted",
"unexported",
"Unpadded",
"unpadding",
"unpads",
"vsub",
"wmctrl"
"Warnf",
"Warningf",
"wmctrl",
"Yousefvand"
],
"favorites.resources": []
}
22 changes: 21 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,26 @@
# Change Log

## Release [date]
## Release: September 27, 2021

### secretserviced v0.2.0

- Support for CLI interface

### secretservice v0.1.0

- CLI interface:
- ping
- export database
- encrypt
- decrypt

### config v0.2.0

- AllowDbExport

### database v0.1.0

## Release: Jun 28, 2021

### secretserviced v0.1.0

Expand Down
57 changes: 51 additions & 6 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -24,15 +24,16 @@ By using **secret service**, you don't need to use `KeePassXC` _secretservice_ f

There is a `scripts/manage.sh` shellscript that do the job of install/uninstall (run it by `./scripts/manage.sh`) but here are the details:

You need to copy the binary (`secretserviced`, build the project or download it from [releases](https://github.com/yousefvand/secret-service/releases) page) some where usually `/usr/bin` but if you don't have the permission, `~/.local/bin` is OK too. To build the binary from source code:
You need to copy the binaries (`secretserviced` and `secretservice`, build the project or download it from [releases](https://github.com/yousefvand/secret-service/releases) page) some where usually `/usr/bin` but if you don't have the permission, `~/.local/bin` is OK too. To build the binaries from source code:

```bash
git clone https://github.com/yousefvand/secret-service.git
cd secret-service
go build -race -o secretserviced cmd/app/secretserviced/main.go
go build -race -o secretservice cmd/app/secretservice/main.go
```

You need a `systemd` **UNIT** file named `secretserviced.service` to put in `/etc/systemd/user` but if you don't have the permission `~/.config/systemd/user` is OK too. Here is a sample **UNIT** file, change `WorkingDirectory` and `ExecStart` according to where you put the binary:
You need a `systemd` **UNIT** file named `secretserviced.service` to put in `/etc/systemd/user` but if you don't have the permission `~/.config/systemd/user` is OK too. Here is a sample **UNIT** file, change `WorkingDirectory` and `ExecStart` according to where you put the binary (`secretserviced`):

```config
[Unit]
Expand Down Expand Up @@ -83,6 +84,50 @@ By default all secrets are encrypted with `AES-CBC-256` symmetric algorithm with

If service refuses to start and you see `OS` exit code `5` in logs, it means som other application has taken dbus name `org.freedesktop.secrets` before (such as keyrings), stop that application and try again.

## secretservice

This binary is the `CLI` interface to communicate with `secretserviced` daemon. Supported commands:

### ping

```bash
secretservice ping
```

Check if service is up and responsive.

### export db

```bash
secretservice export db
```

Export a copy of current db in `~/.secret-service/secretserviced/`. This copy is not encrypted.

### encrypt

```bash
secretservice encrypt -p|--password 32character-password -i|--input /path/to/input/file/ -o|--output /path/to/output/file/
```

Encrypts input file using given password. Password should be exactly 32 character. Example:

```bash
secretservice encrypt -p 012345678901234567890123456789ab -i ~/a.json -o ~/b.json
```

### decrypt

```bash
secretservice decrypt -p|--password 32character-password -i|--input /path/to/input/file/ -o|--output /path/to/output/file/
```

Decrypts input file using given password. Password should be exactly 32 character. Example:

```bash
secretservice decrypt -p 012345678901234567890123456789ab -i ~/a.json -o ~/b.json
```

## Contribution

This project is in its infancy and as it is my first golang project there are many design and code problems. I do appreciate suggestions and **PR**s. If you can get done any item from `TODO` list, you are welcome. This list will be updated based on new insights and user issues.
Expand All @@ -96,10 +141,10 @@ In case of sending a **PR** please make sure:

### TODO

- [ ] Improve CI
- [ ] Improve CI

- [ ] What's the best way to secure `/etc/systemd/user/secretserviced.service` file
- [ ] What's the best way to secure `/etc/systemd/user/secretserviced.service` file

- [ ] deb, rpm, AppImage packages
- [ ] deb, rpm, AppImage packages

- [ ] ...
- [ ] ...
92 changes: 92 additions & 0 deletions cmd/app/secretservice/cmd/decrypt.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,92 @@
package cmd

import (
"bufio"
"io/ioutil"
"os"
"strings"

"github.com/spf13/cobra"
"github.com/yousefvand/secret-service/pkg/crypto"
)

func init() {
rootCmd.AddCommand(decryptCmd)
decryptCmd.Flags().StringP("password", "p", "", "database password")

decryptCmd.Flags().StringP("input", "i", "", "input file")
decryptCmd.Flags().StringP("output", "o", "", "output file")
}

var decryptCmd = &cobra.Command{
Use: "decrypt",
Short: "decrypt a database",
Long: `decrypt a credential database using provided password`,
Run: func(cmd *cobra.Command, _ []string) {

password, _ := cmd.Flags().GetString("password")
input, _ := cmd.Flags().GetString("input")
output, _ := cmd.Flags().GetString("output")

if len(password) != 32 {
panic("Wrong password length. Password should be exactly 32 characters.")
}

if exist, _ := fileOrFolderExists(input); !exist {
panic("Input file doesn't exist")
}

file, err := os.Open(input)

if err != nil {
panic("failed to open input file")
}
defer file.Close()

scanner := bufio.NewScanner(file)
scanner.Split(bufio.ScanLines)
var i int = 0
var signature bool = false
var decrypted []string

for scanner.Scan() {
i++
line := scanner.Text()
if line == " \"encrypted\": true," {
signature = true
}
if i > 2 && !signature {
panic("Wrong type of file. This file is not marked as \"encrypted\"!")
}
if index := strings.Index(line, "secretText"); index > 0 {
cipher := line[21 : len(line)-1]
decrypt, err := crypto.DecryptAESCBC256(password, cipher)
if err != nil {
panic("Decryption failed: " + err.Error())
}
newLine := line[:21] + decrypt + "\""
decrypted = append(decrypted, newLine)
} else {
decrypted = append(decrypted, line)
}
}

fileContent := strings.Join(decrypted, "\n")
err = ioutil.WriteFile(output, []byte(fileContent), 0755)
if err != nil {
panic("Writing to output file failed: " + output)
}

},
}

func fileOrFolderExists(path string) (bool, error) {
_, err := os.Stat(path)
if err == nil {
return true, nil
}
if os.IsNotExist(err) {
return false, nil
}
return false, err
}
81 changes: 81 additions & 0 deletions cmd/app/secretservice/cmd/encrypt.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
package cmd

import (
"bufio"
"io/ioutil"
"os"
"strings"

"github.com/spf13/cobra"
"github.com/yousefvand/secret-service/pkg/crypto"
)

func init() {
rootCmd.AddCommand(encryptCmd)
encryptCmd.Flags().StringP("password", "p", "", "database password")

encryptCmd.Flags().StringP("input", "i", "", "input file")
encryptCmd.Flags().StringP("output", "o", "", "output file")
}

var encryptCmd = &cobra.Command{
Use: "encrypt",
Short: "encrypt a database",
Long: `encrypt a credential database using provided password`,
Run: func(cmd *cobra.Command, _ []string) {

password, _ := cmd.Flags().GetString("password")
input, _ := cmd.Flags().GetString("input")
output, _ := cmd.Flags().GetString("output")

if len(password) != 32 {
panic("Wrong password length. Password should be exactly 32 characters.")
}

if exist, _ := fileOrFolderExists(input); !exist {
panic("Input file doesn't exist")
}

file, err := os.Open(input)

if err != nil {
panic("failed to open input file")
}
defer file.Close()

scanner := bufio.NewScanner(file)
scanner.Split(bufio.ScanLines)
var i int = 0
var signature bool = false
var encrypted []string

for scanner.Scan() {
i++
line := scanner.Text()
if line == " \"encrypted\": false," {
signature = true
}
if i > 2 && !signature {
panic("Wrong type of file. This file is not marked as non \"encrypted\"!")
}
if index := strings.Index(line, "secretText"); index > 0 {
text := line[21 : len(line)-1]
cipher, err := crypto.EncryptAESCBC256(password, text)
if err != nil {
panic("Encryption failed: " + err.Error())
}
newLine := line[:21] + cipher + "\""
encrypted = append(encrypted, newLine)
} else {
encrypted = append(encrypted, line)
}
}

fileContent := strings.Join(encrypted, "\n")
err = ioutil.WriteFile(output, []byte(fileContent), 0755)
if err != nil {
panic("Writing to output file failed: " + output)
}

},
}
29 changes: 29 additions & 0 deletions cmd/app/secretservice/cmd/export_db.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
package cmd

import (
"fmt"

"github.com/spf13/cobra"
"github.com/yousefvand/secret-service/pkg/client"
)

func init() {
rootCmd.AddCommand(exportDbCmd)
}

var exportDbCmd = &cobra.Command{
Use: "export db",
Short: "export db exports an unencrypted version of db",
Long: `export db exports an unencrypted version of credentials database`,
Run: func(_ *cobra.Command, _ []string) {

ssClient, _ := client.New()
response, _ := ssClient.SecretServiceCommand("export database", "")

if response == "ok" {
fmt.Println("database export completed successfully")
} else {
fmt.Println("database export failed!")
}
},
}
Loading

0 comments on commit d24fe48

Please sign in to comment.