forked from tangled.org/core
Monorepo for Tangled

appview: pages/markup: rewrite links links to camo url

authored by anirudh.fi and committed by Tangled 7edbc446 5984e986

Changed files
+57 -16
appview
+2
appview/config.go
··· 13 13 Dev bool `env:"TANGLED_DEV, default=false"` 14 14 JetstreamEndpoint string `env:"TANGLED_JETSTREAM_ENDPOINT, default=wss://jetstream1.us-east.bsky.network/subscribe"` 15 15 ResendApiKey string `env:"TANGLED_RESEND_API_KEY"` 16 + CamoHost string `env:"TANGLED_CAMO_HOST, default=https://camo.tangled.sh"` 17 + CamoSharedSecret string `env:"TANGLED_CAMO_SHARED_SECRET"` 16 18 } 17 19 18 20 func LoadConfig(ctx context.Context) (*Config, error) {
+1 -1
appview/pages/funcmap.go
··· 143 143 return v.Slice(start, end).Interface() 144 144 }, 145 145 "markdown": func(text string) template.HTML { 146 - rctx := &markup.RenderContext{} 146 + rctx := &markup.RenderContext{RendererType: markup.RendererTypeDefault} 147 147 return template.HTML(rctx.RenderMarkdown(text)) 148 148 }, 149 149 "isNil": func(t any) bool {
+31
appview/pages/markup/camo.go
··· 1 + package markup 2 + 3 + import ( 4 + "crypto/hmac" 5 + "crypto/sha256" 6 + "encoding/hex" 7 + "fmt" 8 + 9 + "github.com/yuin/goldmark/ast" 10 + ) 11 + 12 + func generateCamoURL(baseURL, secret, imageURL string) string { 13 + h := hmac.New(sha256.New, []byte(secret)) 14 + h.Write([]byte(imageURL)) 15 + signature := hex.EncodeToString(h.Sum(nil)) 16 + hexURL := hex.EncodeToString([]byte(imageURL)) 17 + return fmt.Sprintf("%s/%s/%s", baseURL, signature, hexURL) 18 + } 19 + 20 + func (rctx *RenderContext) camoImageLinkTransformer(img *ast.Image) { 21 + // don't camo on dev 22 + if rctx.IsDev { 23 + return 24 + } 25 + 26 + dst := string(img.Destination) 27 + 28 + if rctx.CamoUrl != "" && rctx.CamoSecret != "" { 29 + img.Destination = []byte(generateCamoURL(rctx.CamoUrl, rctx.CamoSecret, dst)) 30 + } 31 + }
+12 -1
appview/pages/markup/markdown.go
··· 21 21 const ( 22 22 // RendererTypeRepoMarkdown is for repository documentation markdown files 23 23 RendererTypeRepoMarkdown RendererType = iota 24 + // RendererTypeDefault is non-repo markdown, like issues/pulls/comments. 25 + RendererTypeDefault 24 26 ) 25 27 26 28 // RenderContext holds the contextual data for rendering markdown. 27 29 // It can be initialized empty, and that'll skip any transformations. 28 30 type RenderContext struct { 31 + CamoUrl string 32 + CamoSecret string 29 33 repoinfo.RepoInfo 30 34 IsDev bool 31 35 RendererType RendererType ··· 73 77 a.rctx.relativeLinkTransformer(n.(*ast.Link)) 74 78 case *ast.Image: 75 79 a.rctx.imageFromKnotTransformer(n.(*ast.Image)) 80 + a.rctx.camoImageLinkTransformer(n.(*ast.Image)) 76 81 } 77 - // more types here like RendererTypeIssue/Pull etc. 82 + 83 + case RendererTypeDefault: 84 + switch n.(type) { 85 + case *ast.Image: 86 + a.rctx.imageFromKnotTransformer(n.(*ast.Image)) 87 + a.rctx.camoImageLinkTransformer(n.(*ast.Image)) 88 + } 78 89 } 79 90 80 91 return ast.WalkContinue, nil
+10 -13
appview/pages/pages.go
··· 15 15 "path/filepath" 16 16 "strings" 17 17 18 + "tangled.sh/tangled.sh/core/appview" 18 19 "tangled.sh/tangled.sh/core/appview/auth" 19 20 "tangled.sh/tangled.sh/core/appview/db" 20 21 "tangled.sh/tangled.sh/core/appview/pages/markup" ··· 44 45 rctx *markup.RenderContext 45 46 } 46 47 47 - func NewPages(dev bool) *Pages { 48 + func NewPages(config *appview.Config) *Pages { 48 49 // initialized with safe defaults, can be overriden per use 49 50 rctx := &markup.RenderContext{ 50 - IsDev: dev, 51 + IsDev: config.Dev, 52 + CamoUrl: config.CamoHost, 53 + CamoSecret: config.CamoSharedSecret, 51 54 } 52 55 53 56 p := &Pages{ 54 57 t: make(map[string]*template.Template), 55 - dev: dev, 58 + dev: config.Dev, 56 59 embedFS: Files, 57 60 rctx: rctx, 58 61 templateDir: "appview/pages", ··· 380 383 return p.executeRepo("repo/empty", w, params) 381 384 } 382 385 383 - p.rctx = &markup.RenderContext{ 384 - RepoInfo: params.RepoInfo, 385 - IsDev: p.dev, 386 - RendererType: markup.RendererTypeRepoMarkdown, 387 - } 386 + p.rctx.RepoInfo = params.RepoInfo 387 + p.rctx.RendererType = markup.RendererTypeRepoMarkdown 388 388 389 389 if params.ReadmeFileName != "" { 390 390 var htmlString string ··· 521 521 if params.ShowRendered { 522 522 switch markup.GetFormat(params.Path) { 523 523 case markup.FormatMarkdown: 524 - p.rctx = &markup.RenderContext{ 525 - RepoInfo: params.RepoInfo, 526 - IsDev: p.dev, 527 - RendererType: markup.RendererTypeRepoMarkdown, 528 - } 524 + p.rctx.RepoInfo = params.RepoInfo 525 + p.rctx.RendererType = markup.RendererTypeRepoMarkdown 529 526 params.RenderedContents = template.HTML(p.rctx.RenderMarkdown(params.Contents)) 530 527 } 531 528 }
+1 -1
appview/state/state.go
··· 55 55 56 56 clock := syntax.NewTIDClock(0) 57 57 58 - pgs := pages.NewPages(config.Dev) 58 + pgs := pages.NewPages(config) 59 59 60 60 resolver := appview.NewResolver() 61 61