1 package verify
2
3 import (
4 "bytes"
5 "encoding/base64"
6 "encoding/json"
7 "html/template"
8 "image/png"
9 "net/http"
10
11 "github.com/alecthomas/chroma/formatters/html"
12 "github.com/alecthomas/chroma/lexers"
13 "github.com/alecthomas/chroma/styles"
14 "github.com/boombuler/barcode"
15 "github.com/boombuler/barcode/code128"
16 "github.com/boombuler/barcode/qr"
17
18 "edge-infra.dev/pkg/edge/iam/verify/templates"
19
20 "github.com/coreos/go-oidc/v3/oidc"
21 "github.com/gin-gonic/gin"
22 "github.com/golang-jwt/jwt/v4"
23 "golang.org/x/oauth2"
24 )
25
26 type TokenSet struct {
27 AccessToken *jwt.Token
28 RefreshToken string
29 IDToken *oidc.IDToken
30 }
31
32 func (v *Verifier) printBarcode(ctx *gin.Context) {
33 result := &Result{
34 Name: "verify print barcode result",
35 Pass: true,
36 Barcode: BarcodeResult{},
37 }
38
39 provider, err := oidc.NewProvider(oidc.InsecureIssuerURLContext(ctx, Issuer()), IssuerURL())
40 if err != nil {
41 step := Step{Name: "setup openid provider", Pass: false}
42 writeResult(ctx, templates.Callback, result, step)
43 return
44 }
45
46
47 var claims struct {
48 Issuer string `json:"issuer"`
49 TokenEndpoint string `json:"token_endpoint"`
50 }
51
52 if err := provider.Claims(&claims); err != nil {
53 step := Step{Name: "provider has valid claims", Pass: false}
54 writeResult(ctx, templates.Callback, result, step)
55 return
56 }
57
58
59 if claims.Issuer != Issuer() {
60
61 step := Step{Name: "issuer on claims is valid", Pass: false}
62 writeResult(ctx, templates.Callback, result, step)
63 return
64 }
65
66
67 if claims.TokenEndpoint != IssuerURL()+oauth2TokenPath {
68
69 step := Step{Name: "token endpoint is correct", Pass: false}
70 writeResult(ctx, templates.Callback, result, step)
71 return
72 }
73
74
75 oauth2Config := oauth2.Config{
76 ClientID: v.ClientID,
77 ClientSecret: v.ClientSecret,
78 RedirectURL: v.ClientURL + verifyCallbackPath,
79 Endpoint: provider.Endpoint(),
80 Scopes: []string{oidc.ScopeOpenID, oidc.ScopeOfflineAccess, "profile"},
81 }
82
83
84 code, _ := ctx.GetQuery("code")
85 redirectURI, _ := ctx.GetQuery("redirect_uri")
86 failureURI, _ := ctx.GetQuery("failure_uri")
87
88
89 barcodeFromCode, err := oauth2Config.Exchange(ctx, code, oauth2.SetAuthURLParam("grant_type", "barcode_code"))
90 if err != nil {
91 step := Step{Name: "exchange barcode code for a barcode", Pass: false}
92 writeResult(ctx, templates.Callback, result, step)
93 return
94 }
95
96 result.Barcode.Token = barcodeFromCode.AccessToken
97 var bc barcode.Barcode
98 if barcodeFromCode.TokenType == "128A" {
99
100 bc, _ = code128.EncodeWithoutChecksum(barcodeFromCode.AccessToken)
101 bc, _ = barcode.Scale(bc, 700, 150)
102 } else {
103 bc, _ = qr.Encode(barcodeFromCode.AccessToken, qr.L, qr.Auto)
104 bc, _ = barcode.Scale(bc, 256, 256)
105 }
106 var buf bytes.Buffer
107 _ = png.Encode(&buf, bc)
108 result.Barcode.Image = base64.StdEncoding.EncodeToString(buf.Bytes())
109
110 result.Barcode.HTML = template.HTML(toHighlightedJSON(barcodeFromCode))
111 result.Barcode.RedirectURI = redirectURI
112 result.Barcode.FailureURI = failureURI
113 steps := make([]Step, 0)
114 steps = append(steps,
115
116 Step{Name: "exchange code for barcode", Pass: barcodeFromCode.Valid()},
117 )
118 writeResult(ctx, templates.PrintBarcode, result, steps...)
119 ctx.Redirect(http.StatusFound, redirectURI)
120 }
121
122 func toHighlightedJSON(any interface{}) string {
123 j, _ := json.MarshalIndent(any, "", " ")
124 lexer := lexers.Get("json")
125 style := styles.Get("github")
126 iterator, _ := lexer.Tokenise(nil, string(j))
127 var b bytes.Buffer
128 formatter := html.New(
129 html.WrapLongLines(true),
130 )
131 _ = formatter.Format(&b, style, iterator)
132 tokenSetFormatted := b.String()
133 return tokenSetFormatted
134 }
135
View as plain text