mirror of
https://github.com/1f349/cardcaldav.git
synced 2024-12-22 00:04:15 +00:00
Make a working test program
This commit is contained in:
parent
65d436e99b
commit
fff0b27a95
88
auth.go
Normal file
88
auth.go
Normal file
@ -0,0 +1,88 @@
|
||||
package cardcaldav
|
||||
|
||||
import (
|
||||
"cardcaldav/database"
|
||||
"context"
|
||||
"errors"
|
||||
"golang.org/x/crypto/bcrypt"
|
||||
"net/http"
|
||||
"strings"
|
||||
|
||||
_ "github.com/go-sql-driver/mysql"
|
||||
)
|
||||
|
||||
type contextKey int
|
||||
|
||||
var authCtxKey contextKey = 0
|
||||
|
||||
type Context struct {
|
||||
UserName string
|
||||
}
|
||||
|
||||
func NewContext(ctx context.Context, a *Context) context.Context {
|
||||
return context.WithValue(ctx, authCtxKey, a)
|
||||
}
|
||||
|
||||
func FromContext(ctx context.Context) (*Context, bool) {
|
||||
a, ok := ctx.Value(authCtxKey).(*Context)
|
||||
return a, ok
|
||||
}
|
||||
|
||||
type ProviderMiddleware interface {
|
||||
Middleware(next http.Handler) http.Handler
|
||||
}
|
||||
|
||||
var authError = errors.New("auth context error")
|
||||
|
||||
type Auth struct {
|
||||
DB *database.Queries
|
||||
}
|
||||
|
||||
func (a *Auth) Middleware(next http.Handler) http.Handler {
|
||||
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
if r.Header.Get("Authorization") == "" {
|
||||
w.Header().Add("WWW-Authenticate", `Basic realm="Please provide a password", charset="UTF-8"`)
|
||||
http.Error(w, "HTTP auth is required", http.StatusUnauthorized)
|
||||
return
|
||||
}
|
||||
username, accessToken, ok := r.BasicAuth()
|
||||
if !ok {
|
||||
http.Error(w, "Authorization invalid", http.StatusUnauthorized)
|
||||
return
|
||||
}
|
||||
|
||||
// validate username and password
|
||||
if a.ValidateCredentials(r.Context(), username, accessToken) != nil {
|
||||
http.Error(w, "Authorization invalid", http.StatusUnauthorized)
|
||||
return
|
||||
}
|
||||
|
||||
r = r.WithContext(NewContext(r.Context(), &Context{UserName: username}))
|
||||
r.BasicAuth()
|
||||
next.ServeHTTP(w, r)
|
||||
})
|
||||
}
|
||||
|
||||
func (a *Auth) CurrentUserPrincipal(ctx context.Context) (string, error) {
|
||||
authCtx, ok := FromContext(ctx)
|
||||
if !ok {
|
||||
return "", authError
|
||||
}
|
||||
return "/" + authCtx.UserName + "/", nil
|
||||
}
|
||||
|
||||
const blfCryptPrefix = "{BLF-CRYPT}"
|
||||
|
||||
var errNotBlfCrypt = errors.New("not BLF crypt")
|
||||
|
||||
func (a *Auth) ValidateCredentials(ctx context.Context, un, pw string) error {
|
||||
hash, err := a.DB.GetPasswordHash(ctx, un)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if !strings.HasPrefix(hash, blfCryptPrefix) {
|
||||
return errNotBlfCrypt
|
||||
}
|
||||
hash = hash[len(blfCryptPrefix):]
|
||||
return bcrypt.CompareHashAndPassword([]byte(hash), []byte(pw))
|
||||
}
|
24
database/auth.sql.go
Normal file
24
database/auth.sql.go
Normal file
@ -0,0 +1,24 @@
|
||||
// Code generated by sqlc. DO NOT EDIT.
|
||||
// versions:
|
||||
// sqlc v1.25.0
|
||||
// source: auth.sql
|
||||
|
||||
package database
|
||||
|
||||
import (
|
||||
"context"
|
||||
)
|
||||
|
||||
const getPasswordHash = `-- name: GetPasswordHash :one
|
||||
SELECT password
|
||||
FROM mailbox
|
||||
WHERE username = ?
|
||||
AND active > 0
|
||||
`
|
||||
|
||||
func (q *Queries) GetPasswordHash(ctx context.Context, username string) (string, error) {
|
||||
row := q.db.QueryRowContext(ctx, getPasswordHash, username)
|
||||
var password string
|
||||
err := row.Scan(&password)
|
||||
return password, err
|
||||
}
|
31
database/db.go
Normal file
31
database/db.go
Normal file
@ -0,0 +1,31 @@
|
||||
// Code generated by sqlc. DO NOT EDIT.
|
||||
// versions:
|
||||
// sqlc v1.25.0
|
||||
|
||||
package database
|
||||
|
||||
import (
|
||||
"context"
|
||||
"database/sql"
|
||||
)
|
||||
|
||||
type DBTX interface {
|
||||
ExecContext(context.Context, string, ...interface{}) (sql.Result, error)
|
||||
PrepareContext(context.Context, string) (*sql.Stmt, error)
|
||||
QueryContext(context.Context, string, ...interface{}) (*sql.Rows, error)
|
||||
QueryRowContext(context.Context, string, ...interface{}) *sql.Row
|
||||
}
|
||||
|
||||
func New(db DBTX) *Queries {
|
||||
return &Queries{db: db}
|
||||
}
|
||||
|
||||
type Queries struct {
|
||||
db DBTX
|
||||
}
|
||||
|
||||
func (q *Queries) WithTx(tx *sql.Tx) *Queries {
|
||||
return &Queries{
|
||||
db: tx,
|
||||
}
|
||||
}
|
13
database/models.go
Normal file
13
database/models.go
Normal file
@ -0,0 +1,13 @@
|
||||
// Code generated by sqlc. DO NOT EDIT.
|
||||
// versions:
|
||||
// sqlc v1.25.0
|
||||
|
||||
package database
|
||||
|
||||
import ()
|
||||
|
||||
type Mailbox struct {
|
||||
Username string `json:"username"`
|
||||
Password string `json:"password"`
|
||||
Active int32 `json:"active"`
|
||||
}
|
6
database/models/mailbox.sql
Normal file
6
database/models/mailbox.sql
Normal file
@ -0,0 +1,6 @@
|
||||
CREATE TABLE mailbox
|
||||
(
|
||||
username VARCHAR(254) PRIMARY KEY UNIQUE NOT NULL,
|
||||
password VARCHAR(256) NOT NULL,
|
||||
active INT NOT NULL
|
||||
);
|
5
database/queries/auth.sql
Normal file
5
database/queries/auth.sql
Normal file
@ -0,0 +1,5 @@
|
||||
-- name: GetPasswordHash :one
|
||||
SELECT password
|
||||
FROM mailbox
|
||||
WHERE username = ?
|
||||
AND active > 0;
|
55
go.sum
Normal file
55
go.sum
Normal file
@ -0,0 +1,55 @@
|
||||
filippo.io/edwards25519 v1.1.0 h1:FNf4tywRC1HmFuKW5xopWpigGjJKiJSV0Cqo0cJWDaA=
|
||||
filippo.io/edwards25519 v1.1.0/go.mod h1:BxyFTGdWcka3PhytdK4V28tE5sGfRvvvRV7EaN4VDT4=
|
||||
github.com/aymanbagabas/go-osc52/v2 v2.0.1 h1:HwpRHbFMcZLEVr42D4p7XBqjyuxQH5SMiErDT4WkJ2k=
|
||||
github.com/aymanbagabas/go-osc52/v2 v2.0.1/go.mod h1:uYgXzlJ7ZpABp8OJ+exZzJJhRNQ2ASbcXHWsFqH8hp8=
|
||||
github.com/charmbracelet/lipgloss v0.10.0 h1:KWeXFSexGcfahHX+54URiZGkBFazf70JNMtwg/AFW3s=
|
||||
github.com/charmbracelet/lipgloss v0.10.0/go.mod h1:Wig9DSfvANsxqkRsqj6x87irdy123SR4dOXlKa91ciE=
|
||||
github.com/charmbracelet/log v0.4.0 h1:G9bQAcx8rWA2T3pWvx7YtPTPwgqpk7D68BX21IRW8ZM=
|
||||
github.com/charmbracelet/log v0.4.0/go.mod h1:63bXt/djrizTec0l11H20t8FDSvA4CRZJ1KH22MdptM=
|
||||
github.com/coreos/go-systemd/v22 v22.5.0/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSVTIJ3seZv2GcEnc=
|
||||
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
|
||||
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/go-logfmt/logfmt v0.6.0 h1:wGYYu3uicYdqXVgoYbvnkrPVXkuLM1p1ifugDMEdRi4=
|
||||
github.com/go-logfmt/logfmt v0.6.0/go.mod h1:WYhtIu8zTZfxdn5+rREduYbwxfcBr/Vr6KEVveWlfTs=
|
||||
github.com/go-sql-driver/mysql v1.8.1 h1:LedoTUt/eveggdHS9qUFC1EFSa8bU2+1pZjSRpvNJ1Y=
|
||||
github.com/go-sql-driver/mysql v1.8.1/go.mod h1:wEBSXgmK//2ZFJyE+qWnIsVGmvmEKlqwuVSjsCm7DZg=
|
||||
github.com/godbus/dbus/v5 v5.0.4/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA=
|
||||
github.com/lucasb-eyer/go-colorful v1.2.0 h1:1nnpGOrhyZZuNyfu1QjKiUICQ74+3FNCN69Aj6K7nkY=
|
||||
github.com/lucasb-eyer/go-colorful v1.2.0/go.mod h1:R4dSotOR9KMtayYi1e77YzuveK+i7ruzyGqttikkLy0=
|
||||
github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA=
|
||||
github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg=
|
||||
github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM=
|
||||
github.com/mattn/go-isatty v0.0.19 h1:JITubQf0MOLdlGRuRq+jtsDlekdYPia9ZFsB8h/APPA=
|
||||
github.com/mattn/go-isatty v0.0.19/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y=
|
||||
github.com/mattn/go-runewidth v0.0.12/go.mod h1:RAqKPSqVFrSLVXbA8x7dzmKdmGzieGRCM46jaSJTDAk=
|
||||
github.com/mattn/go-runewidth v0.0.15 h1:UNAjwbU9l54TA3KzvqLGxwWjHmMgBUVhBiTjelZgg3U=
|
||||
github.com/mattn/go-runewidth v0.0.15/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w=
|
||||
github.com/muesli/reflow v0.3.0 h1:IFsN6K9NfGtjeggFP+68I4chLZV2yIKsXJFNZ+eWh6s=
|
||||
github.com/muesli/reflow v0.3.0/go.mod h1:pbwTDkVPibjO2kyvBQRBxTWEEGDGq0FlB1BIKtnHY/8=
|
||||
github.com/muesli/termenv v0.15.2 h1:GohcuySI0QmI3wN8Ok9PtKGkgkFIk7y6Vpb5PvrY+Wo=
|
||||
github.com/muesli/termenv v0.15.2/go.mod h1:Epx+iuz8sNs7mNKhxzH4fWXGNpZwUaJKRS1noLXviQ8=
|
||||
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
||||
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
|
||||
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||
github.com/rivo/uniseg v0.1.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc=
|
||||
github.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc=
|
||||
github.com/rivo/uniseg v0.4.7 h1:WUdvkW8uEhrYfLC4ZzdpI2ztxP1I582+49Oc5Mq64VQ=
|
||||
github.com/rivo/uniseg v0.4.7/go.mod h1:FN3SvrM+Zdj16jyLfmOkMNblXMcoc8DfTHruCPUcx88=
|
||||
github.com/rs/xid v1.5.0/go.mod h1:trrq9SKmegXys3aeAKXMUTdJsYXVwGY3RLcfgqegfbg=
|
||||
github.com/rs/zerolog v1.32.0 h1:keLypqrlIjaFsbmJOBdB/qvyF8KEtCWHwobLp5l/mQ0=
|
||||
github.com/rs/zerolog v1.32.0/go.mod h1:/7mN4D5sKwJLZQ2b/znpjC3/GQWY/xaDXUM0kKWRHss=
|
||||
github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg=
|
||||
github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
|
||||
golang.org/x/crypto v0.23.0 h1:dIJU/v2J8Mdglj/8rJ6UUOM3Zc9zLZxVZwwxMooUSAI=
|
||||
golang.org/x/crypto v0.23.0/go.mod h1:CKFgDieR+mRhux2Lsu27y0fO304Db0wZe70UKqHu0v8=
|
||||
golang.org/x/exp v0.0.0-20231006140011-7918f672742d h1:jtJma62tbqLibJ5sFQz8bKtEM8rJBtfilJ2qTU199MI=
|
||||
golang.org/x/exp v0.0.0-20231006140011-7918f672742d/go.mod h1:ldy0pHrwJyGW56pPQzzkH36rKxoZW1tw7ZJpeKx+hdo=
|
||||
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.12.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.20.0 h1:Od9JTbYCk261bKm4M/mw7AklTlFYIa0bIp9BgSm1S8Y=
|
||||
golang.org/x/sys v0.20.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
||||
golang.org/x/term v0.20.0 h1:VnkxpohqXaOBYJtBmEppKUG6mXpi+4O6purfc2+sMhw=
|
||||
golang.org/x/term v0.20.0/go.mod h1:8UkIAJTvZgivsXaD6/pH6U9ecQzZ45awqEOzuCvwpFY=
|
||||
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
|
||||
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
47
logger.go
Normal file
47
logger.go
Normal file
@ -0,0 +1,47 @@
|
||||
package cardcaldav
|
||||
|
||||
import (
|
||||
"github.com/charmbracelet/log"
|
||||
"github.com/rs/zerolog"
|
||||
log0 "github.com/rs/zerolog/log"
|
||||
"strings"
|
||||
)
|
||||
|
||||
type zeroToCharmLogger struct{ logger *log.Logger }
|
||||
|
||||
func (z *zeroToCharmLogger) Write(p []byte) (n int, err error) {
|
||||
s := string(p)
|
||||
if len(s) <= 3 {
|
||||
return len(p), nil
|
||||
}
|
||||
inLevel := s[:3]
|
||||
var level log.Level
|
||||
switch inLevel {
|
||||
case "TRC", "DBG":
|
||||
level = log.DebugLevel
|
||||
case "INF":
|
||||
level = log.InfoLevel
|
||||
case "WRN":
|
||||
level = log.WarnLevel
|
||||
case "ERR":
|
||||
level = log.ErrorLevel
|
||||
case "FTL", "PNC":
|
||||
level = log.FatalLevel
|
||||
}
|
||||
z.logger.Helper()
|
||||
translator := z.logger.With()
|
||||
translator.SetCallerFormatter(func(s string, i int, s2 string) string {
|
||||
return "tokidoki internal"
|
||||
})
|
||||
translator.Log(level, strings.TrimSpace(s[4:]))
|
||||
return len(p), nil
|
||||
}
|
||||
|
||||
func SetupLogger(logger *log.Logger) {
|
||||
log0.Logger = log0.Output(zerolog.ConsoleWriter{
|
||||
Out: &zeroToCharmLogger{logger},
|
||||
FormatTimestamp: func(i interface{}) string {
|
||||
return ""
|
||||
},
|
||||
})
|
||||
}
|
Loading…
Reference in New Issue
Block a user