Skip to content

Commit

Permalink
feat: reorganize code
Browse files Browse the repository at this point in the history
Signed-off-by: Carlos A Becker <caarlos0@gmail.com>
  • Loading branch information
caarlos0 committed Mar 8, 2022
1 parent 3df7fdf commit ac3704e
Show file tree
Hide file tree
Showing 13 changed files with 304 additions and 100 deletions.
32 changes: 32 additions & 0 deletions .github/dependabot.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
version: 2
updates:
- package-ecosystem: "gomod"
directory: "/"
schedule:
interval: "daily"
time: "08:00"
labels:
- "dependencies"
commit-message:
prefix: "feat"
include: "scope"
- package-ecosystem: "github-actions"
directory: "/"
schedule:
interval: "daily"
time: "08:00"
labels:
- "dependencies"
commit-message:
prefix: "chore"
include: "scope"
- package-ecosystem: "docker"
directory: "/"
schedule:
interval: "daily"
time: "08:00"
labels:
- "dependencies"
commit-message:
prefix: "feat"
include: "scope"
34 changes: 34 additions & 0 deletions .github/workflows/build.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
name: build

on: [push, pull_request]

jobs:
build:
strategy:
matrix:
os: [ubuntu-latest, macos-latest, windows-latest]
runs-on: ${{ matrix.os }}
env:
GO111MODULE: "on"
steps:
- name: Install Go
uses: actions/setup-go@v2
with:
go-version: ~1.17

- name: Checkout code
uses: actions/checkout@v3

- name: Download Go modules
run: go mod download

- name: Build
run: go build -v ./...

- name: Test
run: go test -v -cover -timeout=30s ./...

snapshot:
uses: charmbracelet/meta/.github/workflows/snapshot.yml@main
secrets:
goreleaser_key: ${{ secrets.GORELEASER_KEY }}
20 changes: 20 additions & 0 deletions .github/workflows/goreleaser.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
name: goreleaser

on:
push:
tags:
- v*.*.*

concurrency:
group: goreleaser
cancel-in-progress: true

jobs:
goreleaser:
uses: charmbracelet/meta/.github/workflows/goreleaser.yml@main
secrets:
docker_username: ${{ secrets.DOCKERHUB_USERNAME }}
docker_token: ${{ secrets.DOCKERHUB_TOKEN }}
gh_pat: ${{ secrets.PERSONAL_ACCESS_TOKEN }}
goreleaser_key: ${{ secrets.GORELEASER_KEY }}
aur_key: ${{ secrets.AUR_KEY }}
28 changes: 28 additions & 0 deletions .github/workflows/lint-soft.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
name: lint-soft
on:
push:
pull_request:

permissions:
contents: read
# Optional: allow read access to pull request. Use with `only-new-issues` option.
pull-requests: read

jobs:
golangci:
name: lint-soft
runs-on: ubuntu-latest
steps:
- name: Install Go
uses: actions/setup-go@v2
with:
go-version: ^1

- uses: actions/checkout@v3
- name: golangci-lint
uses: golangci/golangci-lint-action@v3
with:
# Optional: golangci-lint command line arguments.
args: --config .golangci-soft.yml --issues-exit-code=0
# Optional: show only new issues if it's a pull request. The default value is `false`.
only-new-issues: true
28 changes: 28 additions & 0 deletions .github/workflows/lint.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
name: lint
on:
push:
pull_request:

permissions:
contents: read
# Optional: allow read access to pull request. Use with `only-new-issues` option.
pull-requests: read

jobs:
golangci:
name: lint
runs-on: ubuntu-latest
steps:
- name: Install Go
uses: actions/setup-go@v2
with:
go-version: ^1

- uses: actions/checkout@v3
- name: golangci-lint
uses: golangci/golangci-lint-action@v3
with:
# Optional: golangci-lint command line arguments.
#args:
# Optional: show only new issues if it's a pull request. The default value is `false`.
only-new-issues: true
14 changes: 14 additions & 0 deletions .github/workflows/nightly.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
name: nightly

on:
push:
branches:
- main

jobs:
nightly:
uses: charmbracelet/meta/.github/workflows/nightly.yml@main
secrets:
docker_username: ${{ secrets.DOCKERHUB_USERNAME }}
docker_token: ${{ secrets.DOCKERHUB_TOKEN }}
goreleaser_key: ${{ secrets.GORELEASER_KEY }}
12 changes: 12 additions & 0 deletions .github/workflows/soft-serve.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
name: soft-serve

on:
push:
branches:
- main

jobs:
soft-serve:
uses: charmbracelet/meta/.github/workflows/soft-serve.yml@main
secrets:
ssh-key: "${{ secrets.CHARM_SOFT_SERVE_KEY }}"
17 changes: 17 additions & 0 deletions .goreleaser.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
includes:
- from_url:
url: charmbracelet/meta/main/goreleaser-full.yaml

variables:
main: "./cmd/melt"
description: "Backup and restore SSH keys as mnemonic set of words"
github_url: "https://github.com/charmbracelet/melt"
maintainer: "Carlos A Becker <carlos@charm.sh>"
brew_commit_author_name: "Carlos A Becker"
brew_commit_author_email: "carlos@charm.sh"

before:
hooks:
- ./scripts/manpages.sh
- ./scripts/completions.sh

3 changes: 3 additions & 0 deletions Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
FROM gcr.io/distroless/static
COPY melt /usr/local/bin/melt
ENTRYPOINT [ "/usr/local/bin/melt" ]
83 changes: 3 additions & 80 deletions main.go → cmd/melt/main.go
Original file line number Diff line number Diff line change
@@ -1,20 +1,14 @@
package main

import (
"crypto/ed25519"
"crypto/sha256"
"encoding/hex"
"encoding/pem"
"fmt"
"io"
"os"

"github.com/charmbracelet/lipgloss"
"github.com/charmbracelet/melt"
"github.com/mattn/go-isatty"
"github.com/mikesmitty/edkey"
"github.com/muesli/coral"
"github.com/tyler-smith/go-bip39"
"golang.org/x/crypto/ssh"
)

var (
Expand All @@ -33,7 +27,7 @@ var (
Example: "melt backup ~/.ssh/id_ed25519",
Args: coral.ExactArgs(1),
RunE: func(cmd *coral.Command, args []string) error {
mnemonic, sum, err := backup(args[0])
mnemonic, sum, err := melt.Backup(args[0])
if err != nil {
return err
}
Expand Down Expand Up @@ -66,7 +60,7 @@ Store them somewhere safe, print or memorize them.
Example: "melt restore --mnemonic \"list of words\" ./id_ed25519_restored",
Args: coral.ExactArgs(1),
RunE: func(cmd *coral.Command, args []string) error {
sum, err := restore(args[0], maybeFile(mnemonic), algo)
sum, err := melt.Restore(args[0], maybeFile(mnemonic), algo)
if err != nil {
return err
}
Expand Down Expand Up @@ -97,34 +91,6 @@ func main() {
}
}

func backup(path string) (string, string, error) {
bts, err := os.ReadFile(path)
if err != nil {
return "", "", fmt.Errorf("could not read key: %w", err)
}

key, err := ssh.ParseRawPrivateKey(bts)
if err != nil {
return "", "", fmt.Errorf("could not parse key: %w", err)
}

var seed []byte
switch key := key.(type) {
case *ed25519.PrivateKey:
seed = key.Seed()
default:
return "", "", fmt.Errorf("unknown key type: %v", key)
}

words, err := bip39.NewMnemonic(seed)
if err != nil {
return "", "", fmt.Errorf("could not create a mnemonic for %s: %w", path, err)
}

sum, err := sha256sum(bts)
return words, sum, err
}

func maybeFile(s string) string {
if s == "-" {
bts, err := io.ReadAll(os.Stdin)
Expand All @@ -138,46 +104,3 @@ func maybeFile(s string) string {
}
return string(bts)
}

func restore(path, mnemonic, keyType string) (string, error) {
seed, err := bip39.EntropyFromMnemonic(mnemonic)
if err != nil {
return "", err
}

var bts []byte
var pubkey ssh.PublicKey

switch keyType {
case "ed25519":
pvtKey := ed25519.NewKeyFromSeed(seed)
bts = pem.EncodeToMemory(&pem.Block{
Type: "OPENSSH PRIVATE KEY",
Bytes: edkey.MarshalED25519PrivateKey(pvtKey),
})
pubkey, err = ssh.NewPublicKey(pvtKey.Public())
if err != nil {
return "", fmt.Errorf("could not prepare public key: %w", err)
}
default:
return "", fmt.Errorf("unsupported key type: %q", keyType)
}

if err := os.WriteFile(path, bts, 0o600); err != nil {
return "", fmt.Errorf("failed to write private key: %w", err)
}

if err := os.WriteFile(path+".pub", ssh.MarshalAuthorizedKey(pubkey), 0o655); err != nil {
return "", fmt.Errorf("failed to write public key: %w", err)
}

return sha256sum(bts)
}

func sha256sum(bts []byte) (string, error) {
digest := sha256.New()
if _, err := digest.Write(bts); err != nil {
return "", fmt.Errorf("failed to sha256sum key: %w", err)
}
return hex.EncodeToString(digest.Sum(nil)), nil
}
24 changes: 24 additions & 0 deletions cmd/melt/main_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
package main

import (
"os"
"path/filepath"
"testing"

"github.com/matryer/is"
)

func TestMaybeFile(t *testing.T) {
t.Run("is a file", func(t *testing.T) {
is := is.New(t)
path := filepath.Join(t.TempDir(), "f")
content := "test content"
is.NoErr(os.WriteFile(path, []byte(content), 0o644))
is.Equal(content, maybeFile(path))
})

t.Run("not a file", func(t *testing.T) {
is := is.New(t)
is.Equal("strings", maybeFile("strings"))
})
}
Loading

0 comments on commit ac3704e

Please sign in to comment.