...

Source file src/edge-infra.dev/pkg/edge/iam/verify/verifier_print_barcode.go

Documentation: edge-infra.dev/pkg/edge/iam/verify

     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  	// discover openid config to setup a oauth2 client
    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  	// verify the openid configuration
    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  	// verify the issuer
    59  	if claims.Issuer != Issuer() {
    60  		// "we're not minting tokens as ourselves?"
    61  		step := Step{Name: "issuer on claims is valid", Pass: false}
    62  		writeResult(ctx, templates.Callback, result, step)
    63  		return
    64  	}
    65  
    66  	// verify the token-endpoint
    67  	if claims.TokenEndpoint != IssuerURL()+oauth2TokenPath {
    68  		// "we're not minting tokens as ourselves?"
    69  		step := Step{Name: "token endpoint is correct", Pass: false}
    70  		writeResult(ctx, templates.Callback, result, step)
    71  		return
    72  	}
    73  
    74  	// weirdly named config, but it's a client
    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  	// get the params from the query
    84  	code, _ := ctx.GetQuery("code")
    85  	redirectURI, _ := ctx.GetQuery("redirect_uri")
    86  	failureURI, _ := ctx.GetQuery("failure_uri")
    87  
    88  	// exchange the barcode code for a barcode
    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  		// generate image for the code128 barcode
   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  	//nolint:gosec
   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  		// code --> barcode
   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