From 12b72c447eb5c58f857461db5ca1d4cff60f5ba8 Mon Sep 17 00:00:00 2001 From: Aaron Bieber Date: Sun, 5 Apr 2020 09:33:04 -0600 Subject: [PATCH] make token a bit more complex, update go mod stuffs --- cmd/cromps/main.go | 8 +------- db/db.go | 10 ++++++++++ db/models.go | 2 +- db/queries.sql.go | 44 +++++++++++++++++++++++++++++++---------- go.mod | 6 ++++++ go.sum | 34 +++++++++++++++++++++++++++++++ sql/queries/queries.sql | 10 ++++++++-- sql/schema/schema.sql | 5 ++++- 8 files changed, 98 insertions(+), 21 deletions(-) diff --git a/cmd/cromps/main.go b/cmd/cromps/main.go index c1b5e0d..e911c37 100644 --- a/cmd/cromps/main.go +++ b/cmd/cromps/main.go @@ -8,7 +8,6 @@ import ( "net/http" "time" - "github.com/google/uuid" _ "github.com/lib/pq" "suah.dev/cromp/db" ) @@ -33,12 +32,7 @@ func getUser(r *http.Request) (*db.User, error) { return nil, fmt.Errorf("Unauthorized") } - u, err := uuid.Parse(token) - if err != nil { - return nil, err - } - - user, err := base.GetUserByToken(ctx, u) + user, err := base.GetUserByToken(ctx, token) if err != nil { return nil, err } diff --git a/db/db.go b/db/db.go index e008412..e9347e0 100644 --- a/db/db.go +++ b/db/db.go @@ -55,6 +55,9 @@ func Prepare(ctx context.Context, db DBTX) (*Queries, error) { if q.similarEntriesStmt, err = db.PrepareContext(ctx, similarEntries); err != nil { return nil, fmt.Errorf("error preparing query SimilarEntries: %w", err) } + if q.updateEntryStmt, err = db.PrepareContext(ctx, updateEntry); err != nil { + return nil, fmt.Errorf("error preparing query UpdateEntry: %w", err) + } if q.validTokenStmt, err = db.PrepareContext(ctx, validToken); err != nil { return nil, fmt.Errorf("error preparing query ValidToken: %w", err) } @@ -118,6 +121,11 @@ func (q *Queries) Close() error { err = fmt.Errorf("error closing similarEntriesStmt: %w", cerr) } } + if q.updateEntryStmt != nil { + if cerr := q.updateEntryStmt.Close(); cerr != nil { + err = fmt.Errorf("error closing updateEntryStmt: %w", cerr) + } + } if q.validTokenStmt != nil { if cerr := q.validTokenStmt.Close(); cerr != nil { err = fmt.Errorf("error closing validTokenStmt: %w", cerr) @@ -173,6 +181,7 @@ type Queries struct { getUserStmt *sql.Stmt getUserByTokenStmt *sql.Stmt similarEntriesStmt *sql.Stmt + updateEntryStmt *sql.Stmt validTokenStmt *sql.Stmt } @@ -191,6 +200,7 @@ func (q *Queries) WithTx(tx *sql.Tx) *Queries { getUserStmt: q.getUserStmt, getUserByTokenStmt: q.getUserByTokenStmt, similarEntriesStmt: q.similarEntriesStmt, + updateEntryStmt: q.updateEntryStmt, validTokenStmt: q.validTokenStmt, } } diff --git a/db/models.go b/db/models.go index ad5c85d..97582bb 100644 --- a/db/models.go +++ b/db/models.go @@ -27,6 +27,6 @@ type User struct { Username string `json:"username"` Hash string `json:"hash"` Email string `json:"email"` - Token uuid.UUID `json:"token"` + Token string `json:"token"` TokenExpires time.Time `json:"token_expires"` } diff --git a/db/queries.sql.go b/db/queries.sql.go index c6c2fb1..650854f 100644 --- a/db/queries.sql.go +++ b/db/queries.sql.go @@ -33,7 +33,7 @@ type AuthUserRow struct { LastName string `json:"last_name"` Username string `json:"username"` Email string `json:"email"` - Token uuid.UUID `json:"token"` + Token string `json:"token"` TokenExpires time.Time `json:"token_expires"` Authed bool `json:"authed"` } @@ -109,7 +109,7 @@ type CreateUserParams struct { type CreateUserRow struct { UserID int64 `json:"user_id"` Username string `json:"username"` - Token uuid.UUID `json:"token"` + Token string `json:"token"` TokenExpires time.Time `json:"token_expires"` } @@ -131,14 +131,17 @@ func (q *Queries) CreateUser(ctx context.Context, arg CreateUserParams) (CreateU return i, err } -const deleteEntry = `-- name: DeleteEntry :exec +const deleteEntry = `-- name: DeleteEntry :execrows DELETE FROM entries WHERE entry_id = $1 ` -func (q *Queries) DeleteEntry(ctx context.Context, entryID uuid.UUID) error { - _, err := q.exec(ctx, q.deleteEntryStmt, deleteEntry, entryID) - return err +func (q *Queries) DeleteEntry(ctx context.Context, entryID uuid.UUID) (int64, error) { + result, err := q.exec(ctx, q.deleteEntryStmt, deleteEntry, entryID) + if err != nil { + return 0, err + } + return result.RowsAffected() } const deleteUser = `-- name: DeleteUser :exec @@ -156,7 +159,7 @@ SELECT entry_id, user_id, created_at, updated_at, title, body FROM entries WHERE user_id = (SELECT user_id FROM users WHERE token = $1 limit 1) ` -func (q *Queries) EntriesByToken(ctx context.Context, token uuid.UUID) ([]Entry, error) { +func (q *Queries) EntriesByToken(ctx context.Context, token string) ([]Entry, error) { rows, err := q.query(ctx, q.entriesByTokenStmt, entriesByToken, token) if err != nil { return nil, err @@ -268,7 +271,7 @@ SELECT user_id, created_at, updated_at, first_name, last_name, username, hash, e WHERE token = $1 LIMIT 1 ` -func (q *Queries) GetUserByToken(ctx context.Context, token uuid.UUID) (User, error) { +func (q *Queries) GetUserByToken(ctx context.Context, token string) (User, error) { row := q.queryRow(ctx, q.getUserByTokenStmt, getUserByToken, token) var i User err := row.Scan( @@ -290,7 +293,7 @@ const similarEntries = `-- name: SimilarEntries :many SELECT entry_id, similarity(body, $2) as similarity, ts_headline('english', body, q) as headline, title from entries, - plainto_tsquery($2) q + to_tsquery($2) q WHERE user_id = $1 and similarity(body, $2) > 0.0 order by similarity DESC @@ -337,12 +340,33 @@ func (q *Queries) SimilarEntries(ctx context.Context, arg SimilarEntriesParams) return items, nil } +const updateEntry = `-- name: UpdateEntry :execrows +UPDATE entries SET + title = $2, + body = $3 +WHERE entry_id = $1 +` + +type UpdateEntryParams struct { + EntryID uuid.UUID `json:"entry_id"` + Title string `json:"title"` + Body string `json:"body"` +} + +func (q *Queries) UpdateEntry(ctx context.Context, arg UpdateEntryParams) (int64, error) { + result, err := q.exec(ctx, q.updateEntryStmt, updateEntry, arg.EntryID, arg.Title, arg.Body) + if err != nil { + return 0, err + } + return result.RowsAffected() +} + const validToken = `-- name: ValidToken :one SELECT now() < token_created FROM users WHERE token = $1 LIMIT 1 ` -func (q *Queries) ValidToken(ctx context.Context, token uuid.UUID) (bool, error) { +func (q *Queries) ValidToken(ctx context.Context, token string) (bool, error) { row := q.queryRow(ctx, q.validTokenStmt, validToken, token) var column_1 bool err := row.Scan(&column_1) diff --git a/go.mod b/go.mod index 184c347..f4c7e2c 100644 --- a/go.mod +++ b/go.mod @@ -3,7 +3,13 @@ module suah.dev/cromp go 1.13 require ( + github.com/deckarep/golang-set v1.7.1 // indirect github.com/google/uuid v1.1.1 github.com/lib/pq v1.3.0 + github.com/mingrammer/commonregex v1.0.1 // indirect github.com/peterbourgon/ff/v2 v2.0.0 + golang.org/x/crypto v0.0.0-20200403201458-baeed622b8d8 + gonum.org/v1/gonum v0.7.0 // indirect + gopkg.in/jdkato/prose.v2 v2.0.0-20190814032740-822d591a158c + gopkg.in/neurosnap/sentences.v1 v1.0.6 // indirect ) diff --git a/go.sum b/go.sum index 13d18bb..61b9cdc 100644 --- a/go.sum +++ b/go.sum @@ -1,20 +1,54 @@ github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= +github.com/ajstarks/svgo v0.0.0-20180226025133-644b8db467af/go.mod h1:K08gAheRH3/J6wwsYMMT4xOr94bZjxIelGM0+d/wbFw= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/deckarep/golang-set v1.7.1 h1:SCQV0S6gTtp6itiFrTqI+pfmJ4LN85S1YzhDf9rTHJQ= +github.com/deckarep/golang-set v1.7.1/go.mod h1:93vsz/8Wt4joVM7c2AVqh+YRMiUSc14yDtF28KmMOgQ= +github.com/fogleman/gg v1.2.1-0.20190220221249-0403632d5b90/go.mod h1:R/bRT+9gY/C5z7JzPU0zXsXHKM4/ayA+zqcVNZzPa1k= github.com/fsnotify/fsnotify v1.4.9 h1:hsms1Qyu0jgnwNXIxa+/V/PDsU6CfLf6CNO8H7IWoS4= github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ= +github.com/golang/freetype v0.0.0-20170609003504-e2365dfdc4a0/go.mod h1:E/TSTwGwJL78qG/PmXZO1EjYhfJinVAhrmmHX6Z8B9k= github.com/google/uuid v1.1.1 h1:Gkbcsh/GbpXz7lPftLA3P6TYMwjCLYm83jiFQZF/3gY= github.com/google/uuid v1.1.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/gorilla/securecookie v1.1.1 h1:miw7JPhV+b/lAHSXz4qd/nN9jRiAFV5FwjeKyCS8BvQ= github.com/gorilla/securecookie v1.1.1/go.mod h1:ra0sb63/xPlUeL+yeDciTfxMRAA+MP+HVt/4epWDjd4= github.com/gorilla/sessions v1.2.0 h1:S7P+1Hm5V/AT9cjEcUD5uDaQSX0OE577aCXgoaKpYbQ= github.com/gorilla/sessions v1.2.0/go.mod h1:dk2InVEVJ0sfLlnXv9EAgkf6ecYs/i80K/zI+bUmuGM= +github.com/jung-kurt/gofpdf v1.0.3-0.20190309125859-24315acbbda5/go.mod h1:7Id9E/uU8ce6rXgefFLlgrJj/GYY22cpxn+r32jIOes= github.com/lib/pq v1.3.0 h1:/qkRGz8zljWiDcFvgpwUpwIAPu3r07TDvs3Rws+o/pU= github.com/lib/pq v1.3.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo= +github.com/mingrammer/commonregex v1.0.1 h1:QY0Z1Bl80jw9M3+488HJXPWnZmvtu3UdvxyodP2FTyY= +github.com/mingrammer/commonregex v1.0.1/go.mod h1:/HNZq7qReKgXBxJxce5SOxf33y0il/ZqL4Kxgo2NLcA= github.com/pelletier/go-toml v1.6.0/go.mod h1:5N711Q9dKgbdkxHL+MEfF31hpT7l0S0s/t2kKREewys= github.com/peterbourgon/ff v1.7.0 h1:hknvTgsh90jNBIjPq7xeq32Y9AmSbpXvjrFW4sJwW+A= github.com/peterbourgon/ff/v2 v2.0.0 h1:lx0oYI5qr/FU1xnpNhQ+EZM04gKgn46jyYvGEEqBBbY= github.com/peterbourgon/ff/v2 v2.0.0/go.mod h1:xjwr+t+SjWm4L46fcj/D+Ap+6ME7+HqFzaP22pP5Ggk= +github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= +golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= +golang.org/x/crypto v0.0.0-20200403201458-baeed622b8d8 h1:fpnn/HnJONpIu6hkXi1u/7rR0NzilgWr4T0JmWkEitk= +golang.org/x/crypto v0.0.0-20200403201458-baeed622b8d8/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= +golang.org/x/exp v0.0.0-20180321215751-8460e604b9de/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= +golang.org/x/exp v0.0.0-20180807140117-3d87b88a115f/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= +golang.org/x/exp v0.0.0-20190125153040-c74c464bbbf2/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= +golang.org/x/image v0.0.0-20180708004352-c73c2afc3b81/go.mod h1:ux5Hcp/YLpHSI86hEcLt0YII63i6oz57MZXIpbrjZUs= +golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190412213103-97732733099d h1:+R4KGOnez64A81RvjARKc4UT5/tI9ujCIVX+P5KiHuI= +golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191005200804-aed5e4c7ecf9 h1:L2auWcuQIvxz9xSEqzESnV/QN/gNRXNApHi3fYwl2w0= golang.org/x/sys v0.0.0-20191005200804-aed5e4c7ecf9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +golang.org/x/tools v0.0.0-20180525024113-a5b4c53f6e8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20190206041539-40960b6deb8e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +gonum.org/v1/gonum v0.0.0-20180816165407-929014505bf4/go.mod h1:Y+Yx5eoAFn32cQvJDxZx5Dpnq+c3wtXuadVZAcxbbBo= +gonum.org/v1/gonum v0.7.0 h1:Hdks0L0hgznZLG9nzXb8vZ0rRvqNvAcgAp84y7Mwkgw= +gonum.org/v1/gonum v0.7.0/go.mod h1:L02bwd0sqlsvRv41G7wGWFCsVNZFv/k1xzGIxeANHGM= +gonum.org/v1/netlib v0.0.0-20190313105609-8cb42192e0e0/go.mod h1:wa6Ws7BG/ESfp6dHfk7C6KdzKA7wR7u/rKwOGE66zvw= +gonum.org/v1/plot v0.0.0-20190515093506-e2840ee46a6b/go.mod h1:Wt8AAjI+ypCyYX3nZBvf6cAIx93T+c/OS2HFAYskSZc= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/jdkato/prose.v2 v2.0.0-20190814032740-822d591a158c h1:co085k1g+uJtaCJ8j/6HyxVtRZWI4PuhRqoIg2+WMXc= +gopkg.in/jdkato/prose.v2 v2.0.0-20190814032740-822d591a158c/go.mod h1:1uCyb8jSeRMeIfMJgVyxYssmCTAlxLBkueX+Iu2UilA= +gopkg.in/neurosnap/sentences.v1 v1.0.6 h1:v7ElyP020iEZQONyLld3fHILHWOPs+ntzuQTNPkul8E= +gopkg.in/neurosnap/sentences.v1 v1.0.6/go.mod h1:YlK+SN+fLQZj+kY3r8DkGDhDr91+S3JmTb5LSxFRQo0= gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +rsc.io/pdf v0.1.1/go.mod h1:n8OzWcQ6Sp37PL01nO98y4iUCRdTGarVfzxY20ICaU4= diff --git a/sql/queries/queries.sql b/sql/queries/queries.sql index 7bd0553..7feb10f 100644 --- a/sql/queries/queries.sql +++ b/sql/queries/queries.sql @@ -6,6 +6,12 @@ INSERT INTO entries ( ) RETURNING entry_id, created_at, to_tsvector(body); +-- name: UpdateEntry :execrows +UPDATE entries SET + title = $2, + body = $3 +WHERE entry_id = $1; + -- name: GetEntry :one SELECT * FROM entries WHERE entry_id = $1 LIMIT 1; @@ -14,7 +20,7 @@ WHERE entry_id = $1 LIMIT 1; SELECT * FROM entries WHERE user_id = $1; --- name: DeleteEntry :exec +-- name: DeleteEntry :execrows DELETE FROM entries WHERE entry_id = $1; @@ -22,7 +28,7 @@ WHERE entry_id = $1; SELECT entry_id, similarity(body, $2) as similarity, ts_headline('english', body, q) as headline, title from entries, - plainto_tsquery($2) q + to_tsquery($2) q WHERE user_id = $1 and similarity(body, $2) > 0.0 order by similarity DESC diff --git a/sql/schema/schema.sql b/sql/schema/schema.sql index 48ee1cb..e1ef5e9 100644 --- a/sql/schema/schema.sql +++ b/sql/schema/schema.sql @@ -13,7 +13,7 @@ CREATE TABLE users ( username text NOT NULL UNIQUE, hash text NOT NULL, email text NOT NULL, - token UUID NOT NULL default gen_random_uuid() UNIQUE, + token text NOT NULL default encode(digest(gen_random_uuid()::text || now(), 'sha256'), 'hex') UNIQUE, token_expires timestamp NOT NULL DEFAULT NOW() + INTERVAL '3 days' ); @@ -31,3 +31,6 @@ CREATE INDEX body_trgm_idx ON entries USING gist (body gist_trgm_ops); CREATE OR REPLACE FUNCTION hash(password text) RETURNS text AS $$ SELECT crypt(password, gen_salt('bf', 10)); $$ LANGUAGE SQL; + +-- CREATE OR REPLACE FUNCTION similar_entries(user_id bigserial, body text, OUT entry_id UUID, OUT similarity float, OUT headline text) AS $$ +-- $$ LANGUAGE SQL;