-
Notifications
You must be signed in to change notification settings - Fork 12
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
core: kgw cookie on multi providers #691
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -5,8 +5,10 @@ import ( | |
"encoding/json" | ||
"fmt" | ||
"net/http" | ||
"net/url" | ||
"os" | ||
"path/filepath" | ||
"strings" | ||
"time" | ||
|
||
"github.com/kwilteam/kwil-db/cmd/kwil-cli/config" | ||
|
@@ -77,6 +79,30 @@ func convertToHttpCookie(c cookie) *http.Cookie { | |
} | ||
} | ||
|
||
// getDomain returns the domain of the URL. | ||
func getDomain(target string) (string, error) { | ||
if target == "" { | ||
return "", fmt.Errorf("target is empty") | ||
} | ||
|
||
if !(strings.HasPrefix(target, "http://") || strings.HasPrefix(target, "https://")) { | ||
return "", fmt.Errorf("target missing scheme") | ||
} | ||
|
||
parsedTarget, err := url.Parse(target) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. One quirk of
We'll probably be rejecting or erroring on such a target before we reach
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. ah I got screwed every time I use |
||
if err != nil { | ||
return "", fmt.Errorf("parse target: %w", err) | ||
} | ||
|
||
return parsedTarget.Scheme + "://" + parsedTarget.Host, nil | ||
} | ||
|
||
// getCookieIdentifier returns a unique identifier for a cookie, base64 encoded. | ||
func getCookieIdentifier(domain string, userIdentifier []byte) string { | ||
return base64.StdEncoding.EncodeToString( | ||
append([]byte(domain+"_"), userIdentifier...)) | ||
} | ||
|
||
// PersistedCookies is a set of Gateway Auth cookies that can be saved to a file. | ||
// It maps a base64 user identifier to a cookie, ensuring only one cookie per wallet. | ||
// It uses a custom cookie type that is json serializable. | ||
|
@@ -85,7 +111,7 @@ type PersistedCookies map[string]cookie | |
// LoadPersistedCookie loads a persisted cookie from the auth file. | ||
// It will look up the cookie for the given user identifier. | ||
// If nothing is found, it returns nil, nil. | ||
func LoadPersistedCookie(authFile string, userIdentifier []byte) (*http.Cookie, error) { | ||
func LoadPersistedCookie(authFile string, domain string, userIdentifier []byte) (*http.Cookie, error) { | ||
if _, err := os.Stat(authFile); os.IsNotExist(err) { | ||
return nil, nil | ||
} | ||
|
@@ -101,24 +127,23 @@ func LoadPersistedCookie(authFile string, userIdentifier []byte) (*http.Cookie, | |
return nil, fmt.Errorf("unmarshal kgw auth file: %w", err) | ||
} | ||
|
||
b64Identifier := base64.StdEncoding.EncodeToString(userIdentifier) | ||
b64Identifier := getCookieIdentifier(domain, userIdentifier) | ||
cookie := aInfo[b64Identifier] | ||
|
||
return convertToHttpCookie(cookie), nil | ||
} | ||
|
||
// SaveCookie saves the cookie to auth file. | ||
// It will overwrite the cookie if the address already exists. | ||
func SaveCookie(authFile string, userIdentifier []byte, originCookie *http.Cookie) error { | ||
func SaveCookie(authFile string, domain string, userIdentifier []byte, originCookie *http.Cookie) error { | ||
b64Identifier := getCookieIdentifier(domain, userIdentifier) | ||
cookie := convertToCookie(originCookie) | ||
|
||
authInfoBytes, err := utils.ReadOrCreateFile(authFile) | ||
if err != nil { | ||
return fmt.Errorf("read kgw auth file: %w", err) | ||
} | ||
|
||
b64Identifier := base64.StdEncoding.EncodeToString(userIdentifier) | ||
|
||
var aInfo PersistedCookies | ||
if len(authInfoBytes) == 0 { | ||
aInfo = make(PersistedCookies) | ||
|
@@ -144,14 +169,12 @@ func SaveCookie(authFile string, userIdentifier []byte, originCookie *http.Cooki | |
|
||
// DeleteCookie will delete a cookie that exists for a given user identifier. | ||
// If no cookie exists for the user identifier, it will do nothing. | ||
func DeleteCookie(authFile string, userIdentifier []byte) error { | ||
func DeleteCookie(authFile string, domain string, userIdentifier []byte) error { | ||
authInfoBytes, err := utils.ReadOrCreateFile(authFile) | ||
if err != nil { | ||
return fmt.Errorf("read kgw auth file: %w", err) | ||
} | ||
|
||
b64Identifier := base64.StdEncoding.EncodeToString(userIdentifier) | ||
|
||
var aInfo PersistedCookies | ||
if len(authInfoBytes) == 0 { | ||
aInfo = make(PersistedCookies) | ||
|
@@ -161,6 +184,8 @@ func DeleteCookie(authFile string, userIdentifier []byte) error { | |
return fmt.Errorf("unmarshal kgw auth file: %w", err) | ||
} | ||
} | ||
|
||
b64Identifier := getCookieIdentifier(domain, userIdentifier) | ||
delete(aInfo, b64Identifier) | ||
|
||
jsonBytes, err := json.MarshalIndent(&aInfo, "", " ") | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -98,14 +98,19 @@ func DialClient(ctx context.Context, cmd *cobra.Command, flags uint8, fn RoundTr | |
return fn(ctx, client, conf) | ||
} | ||
|
||
cookie, err := LoadPersistedCookie(KGWAuthTokenFilePath(), clientConfig.Signer.Identity()) | ||
providerDomain, err := getDomain(conf.Provider) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. When backport, |
||
if err != nil { | ||
return err | ||
} | ||
|
||
cookie, err := LoadPersistedCookie(KGWAuthTokenFilePath(), providerDomain, clientConfig.Signer.Identity()) | ||
if err == nil && cookie != nil { | ||
// if setting fails, then don't do fail usage- failure likely means that the client has | ||
// switched providers, and the cookie is no longer valid. The gatewayclient will re-authenticate. | ||
// delete the cookie if it is invalid | ||
err = client.SetAuthCookie(cookie) | ||
if err != nil { | ||
err2 := DeleteCookie(KGWAuthTokenFilePath(), clientConfig.Signer.Identity()) | ||
err2 := DeleteCookie(KGWAuthTokenFilePath(), providerDomain, clientConfig.Signer.Identity()) | ||
if err2 != nil { | ||
return fmt.Errorf("failed to delete cookie: %w", err2) | ||
} | ||
|
@@ -123,7 +128,7 @@ func DialClient(ctx context.Context, cmd *cobra.Command, flags uint8, fn RoundTr | |
return nil | ||
} | ||
|
||
err = SaveCookie(KGWAuthTokenFilePath(), clientConfig.Signer.Identity(), cookie) | ||
err = SaveCookie(KGWAuthTokenFilePath(), providerDomain, clientConfig.Signer.Identity(), cookie) | ||
if err != nil { | ||
return fmt.Errorf("save cookie: %w", err) | ||
} | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
For 0.7 or v0.6, this should work, since we require scheme https://docs.kwil.com/docs/kwil-cli/configuration#available-configs.
For v0.8, seems this could break?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
you got a pretty handy util function here https://github.com/kwilteam/kwil-db/pull/703/files#diff-7a8b6c70656b28a8bba3d014ad27d1a48efe27f72f184939a4b9d7b5d2313a84R72, I think it will help.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
With latest update to that PR,
cfg.Provider
must be a proper URL now. Another reason to keep that convention I figure.There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The persistened
cfg.Provider
could still be without scheme, am I right?There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Not any more. It's an error:
I think we had that same constraint in v0.7?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We have some unpleasant constraint, like this :
It'll get error when create client, that's before
getDomain
, so I guess we're fine