Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
22 changes: 19 additions & 3 deletions cmd/potok/main.go
Original file line number Diff line number Diff line change
@@ -1,8 +1,24 @@
// Command potok is the Potok command line client.
package main

import "fmt"
import (
"fmt"
"log"
"os"

"github.com/michaeltukdev/Potok/internal/client/cli"
"github.com/michaeltukdev/Potok/internal/client/config"
)

func main() {
fmt.Println("potok: not implemented yet")
cfg, err := config.Load()
if err != nil {
log.Fatal(err)
}

if err := cli.Execute(&cli.Env{
Config: cfg,
}); err != nil {
fmt.Fprintln(os.Stderr, "potok:", err)
os.Exit(1)
}
}
31 changes: 28 additions & 3 deletions cmd/potokd/main.go
Original file line number Diff line number Diff line change
@@ -1,8 +1,33 @@
// Command potokd is the Potok server daemon.
package main

import "fmt"
import (
"context"
"fmt"
"log"
"os"

nethttp "net/http"

"github.com/michaeltukdev/Potok/internal/server/config"
httpapi "github.com/michaeltukdev/Potok/internal/server/http"
"github.com/michaeltukdev/Potok/internal/server/store"
)

func main() {
fmt.Println("potokd: not implemented yet")
cfg, err := config.LoadConfig()
if err != nil {
fmt.Fprintf(os.Stderr, "LoadConfig() error: %v\n", err)
os.Exit(1)
}

conn, err := store.Open(context.Background(), cfg.DatabaseURL)
if err != nil {
fmt.Fprintf(os.Stderr, "Open() error: %v\n", err)
os.Exit(1)
}
defer conn.Close()

handler := httpapi.NewHandler(conn)
nethttp.HandleFunc("GET /health", handler.Health)
log.Fatal(nethttp.ListenAndServe(":3000", nil))
}
22 changes: 22 additions & 0 deletions docker-compose.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
services:
postgres:
image: postgres:17-alpine
container_name: mydb-postgres
restart: unless-stopped
environment:
POSTGRES_USER: ${POSTGRES_USER:-user}
POSTGRES_PASSWORD: ${POSTGRES_PASSWORD:-pass}
POSTGRES_DB: ${POSTGRES_DB:-mydb}
ports:
- "${POSTGRES_PORT:-5442}:5432"
volumes:
- pgdata:/var/lib/postgresql/data
healthcheck:
test: ["CMD-SHELL", "pg_isready -U ${POSTGRES_USER:-user} -d ${POSTGRES_DB:-mydb}"]
interval: 5s
timeout: 5s
retries: 10
start_period: 10s

volumes:
pgdata:
14 changes: 9 additions & 5 deletions go.mod
Original file line number Diff line number Diff line change
@@ -1,13 +1,11 @@
module github.com/michaeltukdev/Potok

go 1.24.0

toolchain go1.24.13
go 1.25.0

require (
github.com/golang-migrate/migrate/v4 v4.18.3
github.com/gorilla/mux v1.8.1
github.com/spf13/cobra v1.9.1
github.com/spf13/cobra v1.10.2
github.com/zalando/go-keyring v0.2.8
golang.org/x/crypto v0.40.0
modernc.org/sqlite v1.38.1
Expand All @@ -26,6 +24,10 @@ require (
github.com/hashicorp/errwrap v1.1.0 // indirect
github.com/hashicorp/go-multierror v1.1.1 // indirect
github.com/inconshreveable/mousetrap v1.1.0 // indirect
github.com/jackc/pgpassfile v1.0.0 // indirect
github.com/jackc/pgservicefile v0.0.0-20240606120523-5a60cdf6a761 // indirect
github.com/jackc/pgx/v5 v5.10.0 // indirect
github.com/jackc/puddle/v2 v2.2.2 // indirect
github.com/joho/godotenv v1.5.1 // indirect
github.com/josephspurrier/goversioninfo v1.4.1 // indirect
github.com/mattn/go-colorable v0.1.13 // indirect
Expand All @@ -35,12 +37,14 @@ require (
github.com/ncruces/zenity v0.10.14 // indirect
github.com/randall77/makefat v0.0.0-20210315173500-7ddd0e42c844 // indirect
github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec // indirect
github.com/spf13/pflag v1.0.6 // indirect
github.com/spf13/pflag v1.0.10 // indirect
go.uber.org/atomic v1.7.0 // indirect
golang.org/x/exp v0.0.0-20250620022241-b7579e27df2b // indirect
golang.org/x/image v0.20.0 // indirect
golang.org/x/sync v0.17.0 // indirect
golang.org/x/sys v0.40.0 // indirect
golang.org/x/term v0.39.0 // indirect
golang.org/x/text v0.29.0 // indirect
modernc.org/libc v1.66.3 // indirect
modernc.org/mathutil v1.7.1 // indirect
modernc.org/memory v1.11.0 // indirect
Expand Down
22 changes: 22 additions & 0 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,17 @@ github.com/gorilla/mux v1.8.1/go.mod h1:AKf9I4AEqPTmMytcMc0KkNouC66V3BtZ4qD5fmWS
github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4=
github.com/hashicorp/errwrap v1.1.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4=
github.com/hashicorp/go-multierror v1.1.1/go.mod h1:iw975J/qwKPdAO1clOe2L8331t/9/fmwbPZ6JB6eMoM=
github.com/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2s0bqwp9tc8=
github.com/inconshreveable/mousetrap v1.1.0/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw=
github.com/jackc/pgpassfile v1.0.0 h1:/6Hmqy13Ss2zCq62VdNG8tM1wchn8zjSGOBJ6icpsIM=
github.com/jackc/pgpassfile v1.0.0/go.mod h1:CEx0iS5ambNFdcRtxPj5JhEz+xB6uRky5eyVu/W2HEg=
github.com/jackc/pgservicefile v0.0.0-20240606120523-5a60cdf6a761 h1:iCEnooe7UlwOQYpKFhBabPMi4aNAfoODPEFNiAnClxo=
github.com/jackc/pgservicefile v0.0.0-20240606120523-5a60cdf6a761/go.mod h1:5TJZWKEWniPve33vlWYSoGYefn3gLQRzjfDlhSJ9ZKM=
github.com/jackc/pgx/v5 v5.10.0 h1:VhSvgU2jSli8o3AqIEOTJr7rZwAEUVo4E4XhR94Zfr0=
github.com/jackc/pgx/v5 v5.10.0/go.mod h1:mal1tBGAFfLHvZzaYh77YS/eC6IX9OWbRV1QIIM0Jn4=
github.com/jackc/puddle/v2 v2.2.2 h1:PR8nw+E/1w0GLuRFSmiioY6UooMp6KJv0/61nB7icHo=
github.com/jackc/puddle/v2 v2.2.2/go.mod h1:vriiEXHvEE654aYKXXjOvZM39qJ0q+azkZFrfEOc3H4=
github.com/joho/godotenv v1.5.1 h1:7eLL/+HRGLY0ldzfGMeQkb7vMd0as4CfYvUVzLqw0N0=
github.com/joho/godotenv v1.5.1/go.mod h1:f4LDr5Voq0i2e/R5DDNOoa2zzDfwtkZa6DnEwAbqwq4=
github.com/josephspurrier/goversioninfo v1.4.1/go.mod h1:JWzv5rKQr+MmW+LvM412ToT/IkYDZjaclF2pKDss8IY=
github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg=
Expand All @@ -31,21 +41,33 @@ github.com/randall77/makefat v0.0.0-20210315173500-7ddd0e42c844/go.mod h1:T1TLSf
github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec/go.mod h1:qqbHyh8v60DhA7CoWK5oRCqLrMHRGoxYCSS9EjAz6Eo=
github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
github.com/spf13/cobra v1.9.1/go.mod h1:nDyEzZ8ogv936Cinf6g1RU9MRY64Ir93oCnqb9wxYW0=
github.com/spf13/cobra v1.10.2 h1:DMTTonx5m65Ic0GOoRY2c16WCbHxOOw6xxezuLaBpcU=
github.com/spf13/cobra v1.10.2/go.mod h1:7C1pvHqHw5A4vrJfjNwvOdzYu0Gml16OCs2GRiTUUS4=
github.com/spf13/pflag v1.0.6/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg=
github.com/spf13/pflag v1.0.9 h1:9exaQaMOCwffKiiiYk6/BndUBv+iRViNW+4lEMi0PvY=
github.com/spf13/pflag v1.0.9/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg=
github.com/spf13/pflag v1.0.10 h1:4EBh2KAYBwaONj6b2Ye1GiHfwjqyROoF4RwYO+vPwFk=
github.com/spf13/pflag v1.0.10/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/zalando/go-keyring v0.2.8 h1:6sD/Ucpl7jNq10rM2pgqTs0sZ9V3qMrqfIIy5YPccHs=
github.com/zalando/go-keyring v0.2.8/go.mod h1:tsMo+VpRq5NGyKfxoBVjCuMrG47yj8cmakZDO5QGii0=
go.uber.org/atomic v1.7.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc=
go.yaml.in/yaml/v3 v3.0.4/go.mod h1:DhzuOOF2ATzADvBadXxruRBLzYTpT36CKvDb3+aBEFg=
golang.org/x/crypto v0.40.0/go.mod h1:Qr1vMER5WyS2dfPHAlsOj01wgLbsyWtFn/aY+5+ZdxY=
golang.org/x/exp v0.0.0-20250620022241-b7579e27df2b/go.mod h1:3//PLf8L/X+8b4vuAfHzxeRUl04Adcb341+IGKfnqS8=
golang.org/x/image v0.20.0/go.mod h1:0a88To4CYVBAHp5FXJm8o7QbUl37Vd85ply1vyD8auM=
golang.org/x/sync v0.17.0 h1:l60nONMj9l5drqw6jlhIELNv9I0A4OFgRsG9k2oT9Ug=
golang.org/x/sync v0.17.0/go.mod h1:9KTHXmSnoGruLpwFjVSX0lNNA75CykiMECbovNTZqGI=
golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.40.0 h1:DBZZqJ2Rkml6QMQsZywtnjnnGvHza6BTfYFWY9kjEWQ=
golang.org/x/sys v0.40.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks=
golang.org/x/term v0.39.0/go.mod h1:yxzUCTP/U+FzoxfdKmLaA0RV1WgE0VY7hXBwKtY/4ww=
golang.org/x/text v0.29.0 h1:1neNs90w9YzJ9BocxfsQNHKuAT4pkghyXc4nhZ6sJvk=
golang.org/x/text v0.29.0/go.mod h1:7MhJOA9CD2qZyOKYazxdYMF85OwPdEr9jTtBpO7ydH4=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
Expand Down
2 changes: 0 additions & 2 deletions internal/client/cli/doc.go

This file was deleted.

37 changes: 37 additions & 0 deletions internal/client/cli/root.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
package cli

import (
"github.com/michaeltukdev/Potok/internal/client/config"
"github.com/spf13/cobra"
)

type Env struct {
Config *config.Config
}

func newRootCmd(env *Env) *cobra.Command {
root := &cobra.Command{
Use: "potok",
Short: "Encrypted backup and sync for Obsidian vaults",
Long: "Potok backs up and syncs Obsidian vaults to a server you control.\n" +
"Vaults are encrypted on this device before upload, so the server\n" +
"never sees your passphrase or your notes.",

SilenceUsage: true,
SilenceErrors: true,

RunE: func(cmd *cobra.Command, _ []string) error {
return cmd.Help()
},
}

root.AddCommand(
runVaultAdd(env),
)

return root
}

func Execute(env *Env) error {
return newRootCmd(env).Execute()
}
44 changes: 44 additions & 0 deletions internal/client/cli/vault.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
package cli

import (
"github.com/spf13/cobra"
)

func runVaultAdd(env *Env) *cobra.Command {
return &cobra.Command{
Use: "vault-add <name>",
Short: "Register a local folder as a vault",
Args: cobra.ExactArgs(1),
RunE: func(cmd *cobra.Command, args []string) error {
// // 1. Validate the name. config.ValidateVaultName already does this.
// if err := config.ValidateVaultName(name); err != nil {
// return err
// }

// // 2. Resolve the path to absolute and check it is a readable directory.
// // Warn (don't fail) if there is no .obsidian folder.

// // 3. Load the config. config.ErrNotFound means run `potok init` first.
// cfg, err := env.Config.Load()
// if errors.Is(err, config.ErrNotFound) {
// return errors.New("not initialised, run `potok init` first")
// }
// if err != nil {
// return err
// }

// // 4. Reject a name that is already registered, before prompting for
// // anything — nobody wants to type a passphrase twice and then be told.

// // 5. Prompt for the passphrase, twice, no echo. Reject empty; reject
// // mismatched.

// // 6. Store the passphrase in the keyring under secrets.VaultKey(name).

// // 7. Add the vault to the config and save. If this fails, delete the
// // keyring entry so a retry isn't blocked by an orphaned passphrase.

return nil
},
}
}
29 changes: 29 additions & 0 deletions internal/client/cli/vault_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
package cli

// func obsidianVault(t *testing.T) string {
// t.Helper()
// dir := t.TempDir()
// if err := os.Mkdir(filepath.Join(dir, ".obsidian"), 0o755); err != nil {
// t.Fatalf("Mkdir(.obsidian) = %v", err)
// }
// return dir
// }

// func TestVaultAdd(t *testing.T) {
// tests := []struct {
// name string
// path string
// passphrase string
// wantErr bool
// }{
// {"key length empty", "", true},
// }

// // Take path
// // Resolve it to absolute
// // Check directory exists and is readable
// // If does not contain .obsidian warn
// // Prompt for a passphrase twice
// // Store under vault:<name>
// // Append to config
// }
Loading
Loading