Skip to content

Commit

Permalink
feat: add custom template edition w/preview [CLI-135]
Browse files Browse the repository at this point in the history
  • Loading branch information
alejofernandez committed Apr 27, 2021
1 parent 4b8fcb5 commit 8ec6585
Show file tree
Hide file tree
Showing 87 changed files with 6,368 additions and 5 deletions.
3 changes: 3 additions & 0 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ require (
github.com/golang/mock v1.5.0
github.com/golang/snappy v0.0.3 // indirect
github.com/google/go-cmp v0.5.5
github.com/guiguan/caster v0.0.0-20191104051807-3736c4464f38
github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51
github.com/klauspost/compress v1.11.9 // indirect
github.com/klauspost/pgzip v1.2.5 // indirect
Expand All @@ -23,8 +24,10 @@ require (
github.com/mgutz/ansi v0.0.0-20200706080929-d51e80ef957d // indirect
github.com/mholt/archiver/v3 v3.5.0
github.com/olekukonko/tablewriter v0.0.5
github.com/phayes/freeport v0.0.0-20180830031419-95f893ade6f2
github.com/pierrec/lz4/v4 v4.1.3 // indirect
github.com/rivo/uniseg v0.2.0 // indirect
github.com/rjeczalik/notify v0.9.2
github.com/spf13/cobra v1.1.3
github.com/spf13/pflag v1.0.5
github.com/spf13/viper v1.7.0
Expand Down
7 changes: 7 additions & 0 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -226,6 +226,8 @@ github.com/gorilla/websocket v1.4.2/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/ad
github.com/grpc-ecosystem/go-grpc-middleware v1.0.0/go.mod h1:FiyG127CGDf3tlThmgyCl78X/SZQqEOJBCDaAfeWzPs=
github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0/go.mod h1:8NvIoxWQoOIhqOTXgfV/d3M/q6VIi02HzZEHgUlZvzk=
github.com/grpc-ecosystem/grpc-gateway v1.9.0/go.mod h1:vNeuVxBJEsws4ogUvrchl83t/GYV9WGTSLVdBhOQFDY=
github.com/guiguan/caster v0.0.0-20191104051807-3736c4464f38 h1:oWETJozNAt29o9b03jPJ8mjQTk8XklRXEZiXBECoNpg=
github.com/guiguan/caster v0.0.0-20191104051807-3736c4464f38/go.mod h1:giU/iWwQIOg/ND1ecR8raoyROxojrXL9osppnuI7MRY=
github.com/hashicorp/consul/api v1.1.0/go.mod h1:VmuI/Lkw1nC05EYQWNKwWGbkg+FbDBtguAZLlVdkD9Q=
github.com/hashicorp/consul/sdk v0.1.1/go.mod h1:VKf9jXwCTEY1QZP2MOLRhb5i/I/ssyNV1vwHyQBF0x8=
github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4=
Expand Down Expand Up @@ -383,6 +385,8 @@ github.com/onsi/gomega v1.7.1/go.mod h1:XdKZgCCFLUoM/7CFJVPcG8C1xQ1AJ0vpAezJrB7J
github.com/pascaldekloe/goe v0.0.0-20180627143212-57f6aae5913c/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc=
github.com/pelletier/go-toml v1.2.0 h1:T5zMGML61Wp+FlcbWjRDT7yAxhJNAiPPLOFECq181zc=
github.com/pelletier/go-toml v1.2.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic=
github.com/phayes/freeport v0.0.0-20180830031419-95f893ade6f2 h1:JhzVVoYvbOACxoUmOs6V/G4D5nPVUW73rKvXxP4XUJc=
github.com/phayes/freeport v0.0.0-20180830031419-95f893ade6f2/go.mod h1:iIss55rKnNBTvrwdmkUpLnDpZoAHvWaiq5+iMmen4AE=
github.com/pierrec/lz4/v4 v4.0.3/go.mod h1:gZWDp/Ze/IJXGXf23ltt2EXimqmTUXEy0GFuRQyBid4=
github.com/pierrec/lz4/v4 v4.1.3 h1:/dvQpkb0o1pVlSgKNQqfkavlnXaIK+hJ0LXsKRUN9D4=
github.com/pierrec/lz4/v4 v4.1.3/go.mod h1:gZWDp/Ze/IJXGXf23ltt2EXimqmTUXEy0GFuRQyBid4=
Expand All @@ -408,6 +412,8 @@ github.com/prometheus/tsdb v0.7.1/go.mod h1:qhTCs0VvXwvX/y3TZrWD7rabWM+ijKTux40T
github.com/rivo/uniseg v0.1.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc=
github.com/rivo/uniseg v0.2.0 h1:S1pD9weZBuJdFmowNwbpi7BJ8TNftyUImj/0WQi72jY=
github.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc=
github.com/rjeczalik/notify v0.9.2 h1:MiTWrPj55mNDHEiIX5YUSKefw/+lCQVoAFmD6oQm5w8=
github.com/rjeczalik/notify v0.9.2/go.mod h1:aErll2f0sUX9PXZnVNyeiObbmTlk5jnMoCa4QEjJeqM=
github.com/rogpeppe/fastuuid v0.0.0-20150106093220-6724a57986af/go.mod h1:XWv6SoW27p1b0cqNHllgS5HIMJraePCO15w5zCzIWYg=
github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4=
github.com/russross/blackfriday v1.5.2/go.mod h1:JO/DiYxRf+HjHt06OyowR9PTA263kcR/rfWxYHBV53g=
Expand Down Expand Up @@ -599,6 +605,7 @@ golang.org/x/sys v0.0.0-20180823144017-11551d06cbcc/go.mod h1:STP8DvDyc/dI5b8T5h
golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20180926160741-c2ed4eda69e7/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20181026203630-95b1ffbd15a5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20181107165924-66b7b1311ac8/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
Expand Down
3 changes: 2 additions & 1 deletion internal/auth/auth.go
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,8 @@ var requiredScopes = []string{
"create:clients", "delete:clients", "read:clients", "update:clients",
"create:resource_servers", "delete:resource_servers", "read:resource_servers", "update:resource_servers",
"create:rules", "delete:rules", "read:rules", "update:rules",
"read:client_keys", "read:logs", "read:users", "update:users",
"read:client_keys", "read:logs", "read:users", "update:users", "read:branding", "update:branding",
"read:tenant_settings",
}

// RequiredScopes returns the scopes used for login.
Expand Down
4 changes: 4 additions & 0 deletions internal/auth0/auth0.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,10 +12,12 @@ type API struct {
ActionVersion ActionVersionAPI
ActionExecution ActionExecutionAPI
ActionBinding ActionBindingAPI
Branding BrandingAPI
Client ClientAPI
Log LogAPI
ResourceServer ResourceServerAPI
Rule RuleAPI
Tenant TenantAPI
User UserAPI
}

Expand All @@ -25,10 +27,12 @@ func NewAPI(m *management.Management) *API {
ActionVersion: m.ActionVersion,
ActionExecution: m.ActionExecution,
ActionBinding: m.ActionBinding,
Branding: m.Branding,
Client: m.Client,
Log: m.Log,
ResourceServer: m.ResourceServer,
Rule: m.Rule,
Tenant: m.Tenant,
User: m.User,
}
}
Expand Down
11 changes: 11 additions & 0 deletions internal/auth0/branding.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
//go:generate mockgen -source=branding.go -destination=branding_mock.go -package=auth0
package auth0

import "gopkg.in/auth0.v5/management"

type BrandingAPI interface {
Read(opts ...management.RequestOption) (b *management.Branding, err error)
UniversalLogin(opts ...management.RequestOption) (ul *management.BrandingUniversalLogin, err error)
SetUniversalLogin(ul *management.BrandingUniversalLogin, opts ...management.RequestOption) (err error)
DeleteUniversalLogin(opts ...management.RequestOption) (err error)
}
8 changes: 8 additions & 0 deletions internal/auth0/tenant.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
//go:generate mockgen -source=tenant.go -destination=tenant_mock.go -package=auth0
package auth0

import "gopkg.in/auth0.v5/management"

type TenantAPI interface {
Read(opts ...management.RequestOption) (t *management.Tenant, err error)
}
162 changes: 162 additions & 0 deletions internal/branding/branding.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,162 @@
package branding

import (
"context"
"encoding/json"
"fmt"
"net"
"net/http"
"path/filepath"
"text/template"
"time"

"github.com/auth0/auth0-cli/internal/open"
"github.com/guiguan/caster"
"github.com/phayes/freeport"
"github.com/rjeczalik/notify"
)

type Client struct {
Id string `json:"id"`
Name string `json:"name"`
LogoUrl string `json:"logo_url,omitempty"`
}

type TemplateData struct {
Filename string
Clients []Client
PrimaryColor string
BackgroundColor string
LogoURL string
TenantName string
Body string
}

func PreviewCustomTemplate(ctx context.Context, templateData TemplateData) {
ctx, cancel := context.WithCancel(ctx)
defer cancel()

address := "localhost"
port, err := freeport.GetFreePort()
if err != nil {
return
}

listener, err := net.Listen("tcp", fmt.Sprintf("%s:%d", address, port))
if err != nil {
return
}

requestTimeout := 10 * time.Minute
server := &http.Server{
Handler: buildRoutes(ctx, requestTimeout, templateData),
ReadTimeout: requestTimeout + 1*time.Minute,
WriteTimeout: requestTimeout + 1*time.Minute,
}
defer server.Close()

go func() {
if err = server.Serve(listener); err != http.ErrServerClosed {
cancel()
}
}()

err = open.URL(fmt.Sprintf("http://%s:%d/data/storybook/?path=/story/universal-login--prompts", address, port))
if err == nil {
return
}

// Wait until the file is closed or input is cancelled
<-ctx.Done()
}

func buildRoutes(ctx context.Context, requestTimeout time.Duration, templateData TemplateData) *http.ServeMux {
router := http.NewServeMux()

// Long polling waiting for file changes
broadcaster := broadcastCustomTemplateChanges(ctx, templateData.Filename)
router.HandleFunc("/dynamic/events", func(w http.ResponseWriter, r *http.Request) {
changes, _ := broadcaster.Sub(r.Context(), 1)
defer broadcaster.Unsub(changes)

var err error
select {
case <-r.Context().Done():
w.WriteHeader(http.StatusGone)
_, err = w.Write([]byte("410 - Gone"))
case <-time.After(requestTimeout):
w.WriteHeader(http.StatusRequestTimeout)
_, err = w.Write([]byte("408 - Request Timeout"))
case <-changes:
w.WriteHeader(http.StatusOK)
_, err = w.Write([]byte("200 - OK"))
}

if err != nil {
http.Error(w, err.Error(), 500)
}
})

// The template file
router.HandleFunc("/dynamic/template", func(w http.ResponseWriter, r *http.Request) {
http.ServeFile(w, r, templateData.Filename)
})

jstmpl := template.Must(template.New("tenant-data.js").Funcs(template.FuncMap{
"asJS": func(v interface{}) string {
a, _ := json.Marshal(v)
return string(a)
},
}).ParseFS(tenantDataAsset, "data/tenant-data.js"))

router.HandleFunc("/dynamic/tenant-data", func(w http.ResponseWriter, r *http.Request) {
err := jstmpl.Execute(w, templateData)
if err != nil {
http.Error(w, err.Error(), 500)
}
})

// Storybook assets
router.Handle("/", http.FileServer(http.FS(templatePreviewAssets)))

return router
}

func broadcastCustomTemplateChanges(ctx context.Context, filename string) *caster.Caster {
publisher := caster.New(ctx)

dir, file := filepath.Split(filename)
c := make(chan notify.EventInfo)
if err := notify.Watch(dir, c, notify.Write); err != nil {
return publisher
}

go func() {
for eventInfo := range c {
if filepath.Base(eventInfo.Path()) == file {
publisher.Pub(true)
}
}
}()

// release resources when the file is closed or the input is cancelled
go func() {
<-ctx.Done()
notify.Stop(c)
close(c)
}()

return publisher
}

func DefaultTemplate() string {
return defaultTemplate
}

func FooterTemplate() string {
return footerTemplate
}

func ImageTemplate() string {
return imageTemplate
}
23 changes: 23 additions & 0 deletions internal/branding/branding_embed.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
package branding

import (
"embed"
_ "embed"
)

var (
//go:embed data/storybook/*
templatePreviewAssets embed.FS

//go:embed data/tenant-data.js
tenantDataAsset embed.FS

//go:embed data/default-template.liquid
defaultTemplate string

//go:embed data/footer-template.liquid
footerTemplate string

//go:embed data/image-template.liquid
imageTemplate string
)
9 changes: 9 additions & 0 deletions internal/branding/data/default-template.liquid
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
<!DOCTYPE html>
<html>
<head>
{%- auth0:head -%}
</head>
<body>
{%- auth0:widget -%}
</body>
</html>
55 changes: 55 additions & 0 deletions internal/branding/data/footer-template.liquid
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
<!DOCTYPE html>
<html lang="{{locale}}">
<head>
{%- auth0:head -%}
<style>
body {
background-image: radial-gradient(white, rgb(200, 200, 200));
}
.footer {
background-color: rgb(120, 120, 120);
position: absolute;
bottom: 0;
left: 0;
padding: 16px 0;
width: 100%;
color: white;
/* Use a high z-index for future-proofing */
z-index: 10;
}
.footer ul {
text-align: center;
}
.footer ul li {
display: inline-block;
margin: 0 4px;
}
.footer ul li:not(:first-of-type) {
margin-left: 0;
}
.footer ul li:not(:first-of-type)::before {
content: '';
display: inline-block;
vertical-align: middle;
width: 4px;
height: 4px;
margin-right: 4px;
background-color: white;
border-radius: 50%;
}
.footer a {
color: white;
}
</style>
<title>{{ prompt.screen.texts.pageTitle }}</title>
</head>
<body class="_widget-auto-layout">
{%- auth0:widget -%}
<footer class="footer">
<ul>
<li><a href="https://company.com/privacy">Privacy Policy</a></li>
<li><a href="https://company.com/terms">Terms of Service</a></li>
</ul>
</footer>
</body>
</html>
Loading

0 comments on commit 8ec6585

Please sign in to comment.