Skip to content
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

Add CookieSameSite DSL #3401

Merged
merged 6 commits into from
Oct 23, 2023
Merged
Show file tree
Hide file tree
Changes from 3 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
28 changes: 28 additions & 0 deletions dsl/http.go
Original file line number Diff line number Diff line change
Expand Up @@ -591,6 +591,34 @@ func CookieHTTPOnly() {
cookieAttribute("http-only", "HttpOnly")
}

// CookieSameSite initializes the "same-site" attribute of a HTTP response
// cookie with "CookieSameSiteStrict", "CookieSameSiteLax", "CookieSameSiteNone",
// or "CookieSameSiteDefault".
//
// CookieSameSite must appear in a Cookie expression.
//
// Example:
//
// var _ = Service("account", func() {
// Method("create", func() {
// Result(Account)
// HTTP(func() {
// Response(StatusCreated, func() {
// Cookie("session:SID", String)
// CookieSameSite(CookieSameSiteStrict)
// })
// })
// })
// })
func CookieSameSite(s expr.CookieSameSiteValue) {
_, ok := eval.Current().(*expr.HTTPResponseExpr)
if !ok {
eval.IncompatibleDSL()
return
}
cookieAttribute("same-site", string(s))
}

// Params groups a set of Param expressions. It makes it possible to list
// required parameters using the Required function.
//
Expand Down
11 changes: 11 additions & 0 deletions expr/attribute.go
Original file line number Diff line number Diff line change
Expand Up @@ -102,6 +102,10 @@ type (
// ValidationFormat is the type used to enumerate the possible string
// formats.
ValidationFormat string

// CookieSameSiteValue is the type used to enumerate the possible cookie
// SameSite values.
CookieSameSiteValue string
)

const (
Expand Down Expand Up @@ -148,6 +152,13 @@ const (
FormatRFC1123 = "rfc1123"
)

const (
CookieSameSiteStrict CookieSameSiteValue = "strict"
CookieSameSiteLax CookieSameSiteValue = "lax"
CookieSameSiteNone CookieSameSiteValue = "none"
CookieSameSiteDefault CookieSameSiteValue = "default"
)

// EvalName returns the name used by the DSL evaluation.
func (*AttributeExpr) EvalName() string {
return "attribute"
Expand Down
1 change: 1 addition & 0 deletions expr/http_cookie_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ func TestHTTPResponseCookie(t *testing.T) {
{"path", testdata.CookiePathDSL, Props{"cookie:path": testdata.CookiePathValue}},
{"secure", testdata.CookieSecureDSL, Props{"cookie:secure": "Secure"}},
{"http-only", testdata.CookieHTTPOnlyDSL, Props{"cookie:http-only": "HttpOnly"}},
{"same-site", testdata.CookieSameSiteDSL, Props{"cookie:same-site": testdata.CookieSameSiteValue}},
}
for _, c := range cases {
t.Run(c.Name, func(t *testing.T) {
Expand Down
20 changes: 20 additions & 0 deletions expr/testdata/cookie_dsls.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package testdata

import (
. "goa.design/goa/v3/dsl"
"goa.design/goa/v3/expr"
)

var CookieObjectResultDSL = func() {
Expand Down Expand Up @@ -124,3 +125,22 @@ var CookieHTTPOnlyDSL = func() {
})
})
}

const CookieSameSiteValue = expr.CookieSameSiteStrict

var CookieSameSiteDSL = func() {
Service("CookieSvc", func() {
Method("Method", func() {
Result(func() {
Attribute("cookie", String)
})
HTTP(func() {
POST("/")
Response(StatusOK, func() {
Cookie("cookie")
CookieSameSite(CookieSameSiteValue)
})
})
})
})
}
3 changes: 3 additions & 0 deletions http/codegen/client.go
Original file line number Diff line number Diff line change
Expand Up @@ -486,6 +486,9 @@ func {{ .RequestEncoder }}(encoder func(*http.Request) goahttp.Encoder) func(*ht
{{- if .HTTPOnly }}
HttpOnly: true,
{{- end }}
{{- if .SameSite }}
SameSite: {{ .SameSite }},
{{- end }}
})
}
{{- end }}
Expand Down
3 changes: 3 additions & 0 deletions http/codegen/server.go
Original file line number Diff line number Diff line change
Expand Up @@ -1352,6 +1352,9 @@ const responseT = `{{ define "response" -}}
{{- if .HTTPOnly }}
HttpOnly: true,
{{- end }}
{{- if .SameSite }}
SameSite: {{ printf "%q" .SameSite }},
Copy link
Contributor Author

@jaredLunde jaredLunde Oct 22, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Will these generated lines print the enum from the net/http package e.g. http.SameSiteLaxMode? It just occurred to me that this could be a problem, as http.SameSite___ are iotas.

Copy link
Contributor Author

@jaredLunde jaredLunde Oct 22, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actually there are a couple of issues with this including the "%q" 😅 Will fix. Where can I add tests for the codegen piece?

{{- end }}
})
{{- if or $checkNil $initDef }}
}
Expand Down
13 changes: 13 additions & 0 deletions http/codegen/service_data.go
Original file line number Diff line number Diff line change
Expand Up @@ -506,6 +506,8 @@ type (
Secure bool
// HTTPOnly sets the cookie "http-only" attribute to "HttpOnly" if true.
HTTPOnly bool
// SameSite sets the cookie "same-site" attribute to the given value.
SameSite http.SameSite
}

// TypeData contains the data needed to render a type definition.
Expand Down Expand Up @@ -2534,6 +2536,17 @@ func extractCookies(a *expr.MappedAttributeExpr, svcAtt *expr.AttributeExpr, svc
c.Secure = v[0] == "Secure"
case "cookie:http-only":
c.HTTPOnly = v[0] == "HttpOnly"
case "cookie:same-site":
switch v[0] {
case string(expr.CookieSameSiteLax):
c.SameSite = http.SameSiteLaxMode
case string(expr.CookieSameSiteStrict):
c.SameSite = http.SameSiteStrictMode
case string(expr.CookieSameSiteNone):
c.SameSite = http.SameSiteNoneMode
case string(expr.CookieSameSiteDefault):
c.SameSite = http.SameSiteDefaultMode
}
}
}
cookies = append(cookies, c)
Expand Down