Skip to content

Commit

Permalink
webmail: rename query string param "token" to "singleUseToken" to be …
Browse files Browse the repository at this point in the history
…less scary in access logs

these singleusetokens can be redeemed once. so when you see it in the logs, it
can't be used again. they are short-lived anyway.

this change should help prevent me periodically investigating token handling...
  • Loading branch information
mjl- committed Aug 23, 2024
1 parent a977082 commit 594182a
Show file tree
Hide file tree
Showing 10 changed files with 35 additions and 29 deletions.
7 changes: 4 additions & 3 deletions webmail/api.go
Original file line number Diff line number Diff line change
Expand Up @@ -130,9 +130,10 @@ func (w Webmail) Logout(ctx context.Context) {
xcheckf(ctx, err, "logout")
}

// Token returns a token to use for an SSE connection. A token can only be used for
// a single SSE connection. Tokens are stored in memory for a maximum of 1 minute,
// with at most 10 unused tokens (the most recently created) per account.
// Token returns a single-use token to use for an SSE connection. A token can only
// be used for a single SSE connection. Tokens are stored in memory for a maximum
// of 1 minute, with at most 10 unused tokens (the most recently created) per
// account.
func (Webmail) Token(ctx context.Context) string {
reqInfo := ctx.Value(requestInfoCtxKey).(requestInfo)
return sseTokens.xgenerate(ctx, reqInfo.Account.Name, reqInfo.LoginAddress, reqInfo.SessionToken)
Expand Down
2 changes: 1 addition & 1 deletion webmail/api.json
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,7 @@
},
{
"Name": "Token",
"Docs": "Token returns a token to use for an SSE connection. A token can only be used for\na single SSE connection. Tokens are stored in memory for a maximum of 1 minute,\nwith at most 10 unused tokens (the most recently created) per account.",
"Docs": "Token returns a single-use token to use for an SSE connection. A token can only\nbe used for a single SSE connection. Tokens are stored in memory for a maximum\nof 1 minute, with at most 10 unused tokens (the most recently created) per\naccount.",
"Params": [],
"Returns": [
{
Expand Down
7 changes: 4 additions & 3 deletions webmail/api.ts
Original file line number Diff line number Diff line change
Expand Up @@ -750,9 +750,10 @@ export class Client {
return await _sherpaCall(this.baseURL, this.authState, { ...this.options }, paramTypes, returnTypes, fn, params) as void
}

// Token returns a token to use for an SSE connection. A token can only be used for
// a single SSE connection. Tokens are stored in memory for a maximum of 1 minute,
// with at most 10 unused tokens (the most recently created) per account.
// Token returns a single-use token to use for an SSE connection. A token can only
// be used for a single SSE connection. Tokens are stored in memory for a maximum
// of 1 minute, with at most 10 unused tokens (the most recently created) per
// account.
async Token(): Promise<string> {
const fn: string = "Token"
const paramTypes: string[][] = []
Expand Down
7 changes: 4 additions & 3 deletions webmail/msg.js
Original file line number Diff line number Diff line change
Expand Up @@ -448,9 +448,10 @@ var api;
const params = [];
return await _sherpaCall(this.baseURL, this.authState, { ...this.options }, paramTypes, returnTypes, fn, params);
}
// Token returns a token to use for an SSE connection. A token can only be used for
// a single SSE connection. Tokens are stored in memory for a maximum of 1 minute,
// with at most 10 unused tokens (the most recently created) per account.
// Token returns a single-use token to use for an SSE connection. A token can only
// be used for a single SSE connection. Tokens are stored in memory for a maximum
// of 1 minute, with at most 10 unused tokens (the most recently created) per
// account.
async Token() {
const fn = "Token";
const paramTypes = [];
Expand Down
7 changes: 4 additions & 3 deletions webmail/text.js
Original file line number Diff line number Diff line change
Expand Up @@ -448,9 +448,10 @@ var api;
const params = [];
return await _sherpaCall(this.baseURL, this.authState, { ...this.options }, paramTypes, returnTypes, fn, params);
}
// Token returns a token to use for an SSE connection. A token can only be used for
// a single SSE connection. Tokens are stored in memory for a maximum of 1 minute,
// with at most 10 unused tokens (the most recently created) per account.
// Token returns a single-use token to use for an SSE connection. A token can only
// be used for a single SSE connection. Tokens are stored in memory for a maximum
// of 1 minute, with at most 10 unused tokens (the most recently created) per
// account.
async Token() {
const fn = "Token";
const paramTypes = [];
Expand Down
5 changes: 3 additions & 2 deletions webmail/view.go
Original file line number Diff line number Diff line change
Expand Up @@ -489,7 +489,8 @@ type ioErr struct {
}

// serveEvents serves an SSE connection. Authentication is done through a query
// string parameter "token", a one-time-use token returned by the Token API call.
// string parameter "singleUseToken", a one-time-use token returned by the Token
// API call.
func serveEvents(ctx context.Context, log mlog.Log, accountPath string, w http.ResponseWriter, r *http.Request) {
if r.Method != "GET" {
http.Error(w, "405 - method not allowed - use get", http.StatusMethodNotAllowed)
Expand All @@ -504,7 +505,7 @@ func serveEvents(ctx context.Context, log mlog.Log, accountPath string, w http.R
}

q := r.URL.Query()
token := q.Get("token")
token := q.Get("singleUseToken")
if token == "" {
http.Error(w, "400 - bad request - missing credentials", http.StatusBadRequest)
return
Expand Down
14 changes: 7 additions & 7 deletions webmail/view_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -131,13 +131,13 @@ func TestView(t *testing.T) {
}
}

testFail("POST", eventsURL+"?token="+tokens[0]+"&request="+string(requestJSON), http.StatusMethodNotAllowed) // Must be GET.
testFail("GET", eventsURL, http.StatusBadRequest) // Missing token.
testFail("GET", eventsURL+"?token="+tokens[0]+"&request="+string(requestJSON), http.StatusBadRequest) // Bad (old) token.
testFail("GET", eventsURL+"?token="+tokens[len(tokens)-5]+"&request=bad", http.StatusBadRequest) // Bad request.
testFail("POST", eventsURL+"?singleUseToken="+tokens[0]+"&request="+string(requestJSON), http.StatusMethodNotAllowed) // Must be GET.
testFail("GET", eventsURL, http.StatusBadRequest) // Missing token.
testFail("GET", eventsURL+"?singleUseToken="+tokens[0]+"&request="+string(requestJSON), http.StatusBadRequest) // Bad (old) token.
testFail("GET", eventsURL+"?singleUseToken="+tokens[len(tokens)-5]+"&request=bad", http.StatusBadRequest) // Bad request.

// Start connection for testing and filters below.
req, err := http.NewRequest("GET", eventsURL+"?token="+tokens[len(tokens)-1]+"&request="+string(requestJSON), nil)
req, err := http.NewRequest("GET", eventsURL+"?singleUseToken="+tokens[len(tokens)-1]+"&request="+string(requestJSON), nil)
tcheck(t, err, "making request")
resp, err := http.DefaultClient.Do(req)
tcheck(t, err, "http transaction")
Expand Down Expand Up @@ -168,15 +168,15 @@ func TestView(t *testing.T) {
}

// Can only use a token once.
testFail("GET", eventsURL+"?token="+tokens[len(tokens)-1]+"&request=bad", http.StatusBadRequest)
testFail("GET", eventsURL+"?singleUseToken="+tokens[len(tokens)-1]+"&request=bad", http.StatusBadRequest)

// Check a few initial query/page combinations.
testConn := func(token, more string, request Request, check func(EventStart, eventReader)) {
t.Helper()

reqJSON, err := json.Marshal(request)
tcheck(t, err, "marshal request json")
req, err := http.NewRequest("GET", eventsURL+"?token="+token+more+"&request="+string(reqJSON), nil)
req, err := http.NewRequest("GET", eventsURL+"?singleUseToken="+token+more+"&request="+string(reqJSON), nil)
tcheck(t, err, "making request")
resp, err := http.DefaultClient.Do(req)
tcheck(t, err, "http transaction")
Expand Down
4 changes: 2 additions & 2 deletions webmail/webmail.go
Original file line number Diff line number Diff line change
Expand Up @@ -194,8 +194,8 @@ func handle(apiHandler http.Handler, isForwarded bool, accountPath string, w htt
log := pkglog.WithContext(ctx).With(slog.String("userauth", ""))

// Server-sent event connection, for all initial data (list of mailboxes), list of
// messages, and all events afterwards. Authenticated through a token in the query
// string, which it got from a Token API call.
// messages, and all events afterwards. Authenticated through a single use token in
// the query string, which it got from a Token API call.
if r.URL.Path == "/events" {
serveEvents(ctx, log, accountPath, w, r)
return
Expand Down
9 changes: 5 additions & 4 deletions webmail/webmail.js
Original file line number Diff line number Diff line change
Expand Up @@ -448,9 +448,10 @@ var api;
const params = [];
return await _sherpaCall(this.baseURL, this.authState, { ...this.options }, paramTypes, returnTypes, fn, params);
}
// Token returns a token to use for an SSE connection. A token can only be used for
// a single SSE connection. Tokens are stored in memory for a maximum of 1 minute,
// with at most 10 unused tokens (the most recently created) per account.
// Token returns a single-use token to use for an SSE connection. A token can only
// be used for a single SSE connection. Tokens are stored in memory for a maximum
// of 1 minute, with at most 10 unused tokens (the most recently created) per
// account.
async Token() {
const fn = "Token";
const paramTypes = [];
Expand Down Expand Up @@ -6911,7 +6912,7 @@ const init = async () => {
}
}
catch (err) { }
eventSource = new window.EventSource('events?token=' + encodeURIComponent(token) + '&request=' + encodeURIComponent(JSON.stringify(request)) + slow);
eventSource = new window.EventSource('events?singleUseToken=' + encodeURIComponent(token) + '&request=' + encodeURIComponent(JSON.stringify(request)) + slow);
let eventID = window.setTimeout(() => dom._kids(statusElem, 'Connecting... '), 1000);
eventSource.addEventListener('open', (e) => {
log('eventsource open', { e });
Expand Down
2 changes: 1 addition & 1 deletion webmail/webmail.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7208,7 +7208,7 @@ const init = async () => {
}
} catch (err) {}

eventSource = new window.EventSource('events?token=' + encodeURIComponent(token)+'&request='+encodeURIComponent(JSON.stringify(request))+slow)
eventSource = new window.EventSource('events?singleUseToken=' + encodeURIComponent(token)+'&request='+encodeURIComponent(JSON.stringify(request))+slow)
let eventID = window.setTimeout(() => dom._kids(statusElem, 'Connecting... '), 1000)
eventSource.addEventListener('open', (e: Event) => {
log('eventsource open', {e})
Expand Down

0 comments on commit 594182a

Please sign in to comment.