feat: add rfc8908 basic api endpoint implementation

This commit is contained in:
wpetit 2021-04-02 09:22:41 +02:00
parent e8b8bbd952
commit 1cc263ca8b
4 changed files with 128 additions and 7 deletions

2
go.mod
View File

@ -5,5 +5,5 @@ go 1.15
require (
github.com/irai/arp v1.3.1
github.com/pkg/errors v0.9.1
gitlab.com/wpetit/goweb v0.0.0-20201116180841-b73723b5f552
gitlab.com/wpetit/goweb v0.0.0-20210329100650-576d5f8548a3
)

10
go.sum
View File

@ -1,5 +1,5 @@
cdr.dev/slog v1.3.0 h1:MYN1BChIaVEGxdS7I5cpdyMC0+WfJfK8BETAfzfLUGQ=
cdr.dev/slog v1.3.0/go.mod h1:C5OL99WyuOK8YHZdYY57dAPN1jK2WJlCdq2VP6xeQns=
cdr.dev/slog v1.4.0 h1:tLXQJ/hZ5Q051h0MBHSd2Ha8xzdXj7CjtzmG/8dUvUk=
cdr.dev/slog v1.4.0/go.mod h1:C5OL99WyuOK8YHZdYY57dAPN1jK2WJlCdq2VP6xeQns=
cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
cloud.google.com/go v0.34.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
cloud.google.com/go v0.38.0/go.mod h1:990N+gfupTy94rShfmMCWGDn0LpTmnzTp2qbd1dvSRU=
@ -127,10 +127,8 @@ github.com/stretchr/testify v1.4.0 h1:2E4SXV/wtOkTonXsotYi4li6zVWxYlZuYNCXe9XRJy
github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
github.com/valyala/bytebufferpool v1.0.0/go.mod h1:6bBcMArwyJ5K/AmCkWv1jt77kVWyCJ6HpOuEn7z0Csc=
github.com/valyala/fasttemplate v1.0.1/go.mod h1:UQGH1tvbgY+Nz5t2n7tXsz52dQxojPUpymEIMZ47gx8=
gitlab.com/wpetit/goweb v0.0.0-20201116180841-b73723b5f552 h1:gr3i9XNCVMlFZi5E88j8qAUlOpvUidMbVn11ho4x7eI=
gitlab.com/wpetit/goweb v0.0.0-20201116180841-b73723b5f552/go.mod h1:Gfv7cBOw1T2XwXMsLm1d9kAjMAdNtLMjPv+yCzRO9qk=
gitlab.com/wpetit/goweb v0.0.0-20210329100043-1c740f83992f h1:SBORCOoEnJ/JTCS71not8Qg36LKvt2Kqk8/7BqE+93c=
gitlab.com/wpetit/goweb v0.0.0-20210329100043-1c740f83992f/go.mod h1:uLIkkm7YE+9mjPLzbCq2GkIiTRN9sJChrEAZjujpqv8=
gitlab.com/wpetit/goweb v0.0.0-20210329100650-576d5f8548a3 h1:9RxyXeV01/vjaAnJb9qbwM5Y+uJQB3XkcvtuxguuIWY=
gitlab.com/wpetit/goweb v0.0.0-20210329100650-576d5f8548a3/go.mod h1:4+weXRJy9RxDw7XnYGP3HrxNWaJhBDZKgiG1E+zRlqw=
go.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU=
go.opencensus.io v0.22.0/go.mod h1:+kGneAE2xo2IficOXnaByMWTGM9T73dGwxeWcUqIpI8=
go.opencensus.io v0.22.2 h1:75k/FF0Q2YM8QYo07VPddOLBslDt1MZOdEslOHvmzAs=

72
rfc8908/handler.go Normal file
View File

@ -0,0 +1,72 @@
package rfc8908
import (
"encoding/json"
"net/http"
"github.com/pkg/errors"
)
type IsCaptiveFunc func(*http.Request) (bool, error)
// RFC8098
// See https://tools.ietf.org/html/rfc8908 - "5. API State Structure"
type Response struct {
Captive bool `json:"captive"`
UserPortalURL string `json:"user-portal-url,omitempty"`
VenueInfoURL string `json:"venue-info-url,omitempty"`
CanExtendSession *bool `json:"can-extend-session,omitempty"`
SecondsRemaining *int `json:"seconds-remaining,omitempty"`
BytesRemaining *int `json:"bytes-remaining,omitempty"`
}
// Handler returns a basic implementation of a Captive Portal API endpoint
// as described in the IETF 8908 RFC (https://tools.ietf.org/html/rfc8908)
func Handler(isCaptive IsCaptiveFunc, opts ...OptionsFunc) http.HandlerFunc {
options := DefaultOptions()
for _, o := range opts {
o(options)
}
return func(w http.ResponseWriter, r *http.Request) {
isCaptive, err := isCaptive(r)
if err != nil {
panic(errors.Wrap(err, "could not retrieve client id"))
}
ctx := r.Context()
var bytesRemaining *int
if options.BytesRemaining != nil {
bytesRemaining, err = options.BytesRemaining(ctx)
if err != nil {
panic(errors.Wrap(err, "could not retrieve client remaining bytes"))
}
}
var secondsRemaining *int
if options.SecondsRemaining != nil {
secondsRemaining, err = options.SecondsRemaining(ctx)
if err != nil {
panic(errors.Wrap(err, "could not retrieve client remaining seconds"))
}
}
w.Header().Add("Content-Type", "application/captive+json")
encoder := json.NewEncoder(w)
res := &Response{
Captive: isCaptive,
VenueInfoURL: options.VenueInfoURL,
UserPortalURL: options.UserPortalURL,
CanExtendSession: options.CanExtendSession,
SecondsRemaining: secondsRemaining,
BytesRemaining: bytesRemaining,
}
if err := encoder.Encode(res); err != nil {
panic(errors.WithStack(err))
}
}
}

51
rfc8908/option.go Normal file
View File

@ -0,0 +1,51 @@
package rfc8908
import "context"
type Options struct {
UserPortalURL string
VenueInfoURL string
CanExtendSession *bool
SecondsRemaining SecondsRemainingFunc
BytesRemaining BytesRemainingFunc
}
type OptionsFunc func(*Options)
type SecondsRemainingFunc func(context.Context) (*int, error)
type BytesRemainingFunc func(context.Context) (*int, error)
func DefaultOptions() *Options {
return &Options{}
}
func WithUserPortalURL(userPortalURL string) OptionsFunc {
return func(o *Options) {
o.UserPortalURL = userPortalURL
}
}
func WithVenueInfoURL(venueInfoURL string) OptionsFunc {
return func(o *Options) {
o.VenueInfoURL = venueInfoURL
}
}
func WithCanExtendSession(canExtend bool) OptionsFunc {
return func(o *Options) {
o.CanExtendSession = &canExtend
}
}
func WithSecondsRemainingFunc(fn SecondsRemainingFunc) OptionsFunc {
return func(o *Options) {
o.SecondsRemaining = fn
}
}
func WithBytesRemainingFunc(fn BytesRemainingFunc) OptionsFunc {
return func(o *Options) {
o.BytesRemaining = fn
}
}