Skip to content

Commit

Permalink
Use custom hostname in all html templates
Browse files Browse the repository at this point in the history
Signed-off-by: Will Norris <will@tailscale.com>
Co-authored-by: Will Norris <will@tailscale.com>
  • Loading branch information
armandocerna and willnorris authored Jul 9, 2024
1 parent 2ca2d9d commit a83ef33
Show file tree
Hide file tree
Showing 9 changed files with 69 additions and 51 deletions.
42 changes: 30 additions & 12 deletions golink.go
Original file line number Diff line number Diff line change
Expand Up @@ -285,19 +285,41 @@ type deleteData struct {
var xsrfKey string

func init() {
homeTmpl = template.Must(template.ParseFS(embeddedFS, "tmpl/base.html", "tmpl/home.html"))
detailTmpl = template.Must(template.ParseFS(embeddedFS, "tmpl/base.html", "tmpl/detail.html"))
successTmpl = template.Must(template.ParseFS(embeddedFS, "tmpl/base.html", "tmpl/success.html"))
helpTmpl = template.Must(template.ParseFS(embeddedFS, "tmpl/base.html", "tmpl/help.html"))
allTmpl = template.Must(template.ParseFS(embeddedFS, "tmpl/base.html", "tmpl/all.html"))
deleteTmpl = template.Must(template.ParseFS(embeddedFS, "tmpl/base.html", "tmpl/delete.html"))
opensearchTmpl = template.Must(template.ParseFS(embeddedFS, "tmpl/opensearch.xml"))
homeTmpl = newTemplate("base.html", "home.html")
detailTmpl = newTemplate("base.html", "detail.html")
successTmpl = newTemplate("base.html", "success.html")
helpTmpl = newTemplate("base.html", "help.html")
allTmpl = newTemplate("base.html", "all.html")
deleteTmpl = newTemplate("base.html", "delete.html")
opensearchTmpl = newTemplate("opensearch.xml")

b := make([]byte, 24)
rand.Read(b)
xsrfKey = base64.StdEncoding.EncodeToString(b)
}

var tmplFuncs = template.FuncMap{
"go": func() string {
return *hostname
},
}

// newTemplate creates a new template with the specified files in the tmpl directory.
// The first file name is used as the template name,
// and tmplFuncs are registered as available funcs.
// This func panics if unable to parse files.
func newTemplate(files ...string) *template.Template {
if len(files) == 0 {
return nil
}
tf := make([]string, 0, len(files))
for _, f := range files {
tf = append(tf, "tmpl/"+f)
}
t := template.New(files[0]).Funcs(tmplFuncs)
return template.Must(t.ParseFS(embeddedFS, tf...))
}

// initStats initializes the in-memory stats counter with counts from db.
func initStats() error {
stats.mu.Lock()
Expand Down Expand Up @@ -473,12 +495,8 @@ func serveHelp(w http.ResponseWriter, _ *http.Request) {
}

func serveOpenSearch(w http.ResponseWriter, _ *http.Request) {
type opensearchData struct {
Hostname string
}

w.Header().Set("Content-Type", "application/opensearchdescription+xml")
opensearchTmpl.Execute(w, opensearchData{Hostname: *hostname})
opensearchTmpl.Execute(w, nil)
}

func serveGo(w http.ResponseWriter, r *http.Request) {
Expand Down
2 changes: 1 addition & 1 deletion tmpl/all.html
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ <h2 class="text-xl font-bold pt-6 pb-2">All Links ({{ len . }} total)</h2>
<tr class="flex hover:bg-gray-100 group border-b border-gray-200">
<td class="flex-1 p-2">
<div class="flex">
<a class="flex-1 hover:text-blue-500 hover:underline" href="/{{ .Short }}">go/{{ .Short }}</a>
<a class="flex-1 hover:text-blue-500 hover:underline" href="/{{ .Short }}">{{go}}/{{ .Short }}</a>
<a class="flex items-center px-2 invisible group-hover:visible" title="Link Details" href="/.detail/{{ .Short }}">
<svg class="hover:fill-blue-500" xmlns="http://www.w3.org/2000/svg" height="1.3em" viewBox="0 0 24 24" width="1.3em" fill="#000000" stroke-width="2"><path d="M0 0h24v24H0V0z" fill="none"/><path d="M11 7h2v2h-2zm0 4h2v6h-2zm1-9C6.48 2 2 6.48 2 12s4.48 10 10 10 10-4.48 10-10S17.52 2 12 2zm0 18c-4.41 0-8-3.59-8-8s3.59-8 8-8 8 3.59 8 8-3.59 8-8 8z"/></svg>
</a>
Expand Down
4 changes: 2 additions & 2 deletions tmpl/base.html
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
<!doctype html>
<html lang="en">
<head>
<title>go/</title>
<title>{{go}}/</title>
<link rel="stylesheet" href="/.static/base.css">
<meta name="viewport" content="width=device-width, initial-scale=1">
<link rel="search" type="application/opensearchdescription+xml" title="searchTitle" href="/.opensearch" />
Expand All @@ -11,7 +11,7 @@
<body class="flex flex-col min-h-screen">
<div class="bg-gray-100 border-b border-gray-200 pt-4 pb-2 mb-6">
<header class="container mx-auto px-4">
<h1 class="text-2xl font-bold pb-1"><a href="/">go/</a></h1>
<h1 class="text-2xl font-bold pb-1"><a href="/">{{go}}/</a></h1>
A private shortlink service for your tailnet
</header>
</div>
Expand Down
4 changes: 2 additions & 2 deletions tmpl/delete.html
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
{{ define "main" }}
<h2 class="text-xl font-bold pb-2">Link go/{{.Short}} Deleted</h2>
<h2 class="text-xl font-bold pb-2">Link {{go}}/{{.Short}} Deleted</h2>

<p class="py-4">Deleted this by mistake? You can recreate the same link below.</p>

<form method="POST" action="/">
<input type="hidden" name="xsrf" value="{{ .XSRF }}" />
<div class="flex flex-wrap">
<div class="flex">
<label for=short class="flex my-2 px-2 items-center bg-gray-100 border border-r-0 border-gray-300 rounded-l-md text-gray-700">http://go/</label>
<label for=short class="flex my-2 px-2 items-center bg-gray-100 border border-r-0 border-gray-300 rounded-l-md text-gray-700">http://{{go}}/</label>
<input id=short name=short required type=text size=15 placeholder="shortname" value="{{.Short}}" pattern="\w[\w\-\.]*" title="Must start with letter or number; may contain letters, numbers, dashes, and periods."
class="p-2 my-2 rounded-r-md border-gray-300 placeholder:text-gray-400 disabled:bg-gray-100">
<span class="flex m-2 items-center">&rarr;</span>
Expand Down
4 changes: 2 additions & 2 deletions tmpl/detail.html
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ <h2 class="text-xl font-bold pb-2">Link Details</h2>
<input type="hidden" name="xsrf" value="{{ .XSRF }}" />
<div class="flex flex-wrap">
<div class="flex">
<label for=short class="flex my-2 px-2 items-center bg-gray-100 border border-r-0 border-gray-300 rounded-l-md text-gray-700">http://go/</label>
<label for=short class="flex my-2 px-2 items-center bg-gray-100 border border-r-0 border-gray-300 rounded-l-md text-gray-700">http://{{go}}/</label>
<input id=short name=short required type=text size=15 placeholder="shortname" value="{{.Link.Short}}" pattern="\w[\w\-\.]*" title="Must start with letter or number; may contain letters, numbers, dashes, and periods."
class="p-2 my-2 rounded-r-md border-gray-300 placeholder:text-gray-400 disabled:bg-gray-100">
<span class="flex m-2 items-center">&rarr;</span>
Expand Down Expand Up @@ -40,7 +40,7 @@ <h3 class="text-lg font-bold pb-2 pt-4 text-red-500">Danger Zone</h3>
{{ else }}
<dl>
<dt class="text-sm font-bold mt-6">Name</dt>
<dd><a class="text-blue-600 hover:underline" href="/{{.Link.Short}}">go/{{.Link.Short}}</a></dd>
<dd><a class="text-blue-600 hover:underline" href="/{{.Link.Short}}">{{go}}/{{.Link.Short}}</a></dd>

<dt class="text-sm font-bold mt-6">Destination</dt>
<dd>{{.Link.Long}}</dd>
Expand Down
48 changes: 24 additions & 24 deletions tmpl/help.html
Original file line number Diff line number Diff line change
@@ -1,19 +1,19 @@
{{ define "main" }}
<article class="prose max-w-5xl">
<p>
go links provide short, memorable links for the websites you and your team use most.
{{go}} links provide short, memorable links for the websites you and your team use most.

<h2>Creating go links</h2>
<h2>Creating {{go}} links</h2>

<p>
All go links have a <strong>short name</strong> and a <strong>destination link</strong> that the go link points to.
All {{go}} links have a <strong>short name</strong> and a <strong>destination link</strong> that the {{go}} link points to.
Some notes on short names:

<ul>
<li>names must start with a letter or number
<li>names may contain letters, numbers, hyphens, and periods
<li>names are <strong>not</strong> case-sensitive (go/foo is the same as go/FOO)
<li>hyphens are ignored when resolving links (go/meetingnotes is the same as go/meeting-notes)
<li>names are <strong>not</strong> case-sensitive ({{go}}/foo is the same as {{go}}/FOO)
<li>hyphens are ignored when resolving links ({{go}}/meetingnotes is the same as {{go}}/meeting-notes)
</ul>

<p>
Expand All @@ -25,26 +25,26 @@ <h2>Creating go links</h2>
<h2>Resolving links</h2>

<p>
When logged in to your Tailscale network, go links can be entered directly into any browser or command line utility such as curl.
When logged in to your Tailscale network, {{go}} links can be entered directly into any browser or command line utility such as curl.
You do not need any additional browser extensions.

<p>
Any additional path provided after the short name will be added to the end of the destination link.
For example, if <strong>go/who</strong> goes to your company directory at <strong>http://directory/</strong>,
then <strong>go/who/amelie</strong> will go to <strong>http://directory/amelie</strong>.
For example, if <strong>{{go}}/who</strong> goes to your company directory at <strong>http://directory/</strong>,
then <strong>{{go}}/who/amelie</strong> will go to <strong>http://directory/amelie</strong>.

<p>
<a href="#advanced">Advanced destination links</a> allow you to further customize this behavior.

<h2 id="advanced">Advanced destination links</h2>

<p>
To have more control over how go links are resolved, destination links can use <a href="https://pkg.go.dev/text/template">Go template syntax</a>.
To have more control over how {{go}} links are resolved, destination links can use <a href="https://pkg.go.dev/text/template">Go template syntax</a>.
Templates are provided a data structure with the following fields:

<ul>
<li><code>.Path</code> is the remaining path value after the short name (without a leading slash).
For the link <strong>go/who/amelie</strong>, the value of <code>.Path</code> is <code>amelie</code>.
For the link <strong>{{go}}/who/amelie</strong>, the value of <code>.Path</code> is <code>amelie</code>.
<li><code>.Now</code> is a <a href="https://pkg.go.dev/time#Time">time.Time</a> value representing the current date and time.
<li><code>.User</code> is the current user resolving the link.
This is the email address of the user or <code>{username}@github</code> for tailnets that use GitHub authentication.
Expand All @@ -61,34 +61,34 @@ <h2 id="advanced">Advanced destination links</h2>

<p>
The most common use of advanced destination links is to put the additional path in a custom location in the destination link.
For example, you might set the destination for <strong>go/search</strong> to:
For example, you might set the destination for <strong>{{go}}/search</strong> to:

<pre>{{`https://www.google.com/{{if .Path}}search?q={{QueryEscape .Path}}{{end}}`}}</pre>

When a user visits <strong>go/search</strong> with no additional path, they will be directed to <a href="https://www.google.com/">https://www.google.com/</a>.
If they include an additional path like <strong>go/search/pangolins</strong>, they will be directed to <a href="https://www.google.com/search?q=pangolins">https://www.google.com/search?q=pangolins</a>.
When a user visits <strong>{{go}}/search</strong> with no additional path, they will be directed to <a href="https://www.google.com/">https://www.google.com/</a>.
If they include an additional path like <strong>{{go}}/search/pangolins</strong>, they will be directed to <a href="https://www.google.com/search?q=pangolins">https://www.google.com/search?q=pangolins</a>.

<h3>Examples</h3>

<table>
<tr>
<td>Include path in query</td>
<td>go/search</td>
<td>{{go}}/search</td>
<td>{{`https://cloudsearch.google.com/{{if .Path}}cloudsearch/search?q={{QueryEscape .Path}}{{end}}`}}</td>
</tr>
<tr>
<td>Include path in destination path</td>
<td>go/slack</td>
<td>{{go}}/slack</td>
<td>{{`https://company.slack.com/{{if .Path}}channels/{{PathEscape .Path}}{{end}}`}}</td>
</tr>
<tr>
<td>Include path in hostname</td>
<td>go/varz</td>
<td>{{go}}/varz</td>
<td>{{`http://{{if .Path}}{{.Path}}{{else}}host{{end}}.example/debug/varz`}}</td>
</tr>
<tr>
<td>Include today's date in wiki page</td>
<td>go/today</td>
<td>{{go}}/today</td>
<td>{{`http://wiki/{{.Now.Format "01-02-2006"}}`}}</td>
</tr>
</table>
Expand All @@ -101,8 +101,8 @@ <h2 id="api">Application Programming Interface (API)</h2>
<p>
Include a "+" after a link to get information about a link without resolving it:

<pre>{{`$ curl -L go/search+
{
<pre>$ curl -L {{go}}/search+
{{`{
"Short": "search",
"Long": "https://cloudsearch.google.com/{{if .Path}}cloudsearch/search?q={{QueryEscape .Path}}{{end}}",
"Created": "2022-06-08T04:27:32.829906577Z",
Expand All @@ -113,19 +113,19 @@ <h2 id="api">Application Programming Interface (API)</h2>
</pre>

<p>
Visit <a href="/.export">go/.export</a> to export all saved links and their metadata in <a href="https://jsonlines.org/">JSON Lines format</a>.
Visit <a href="/.export">{{go}}/.export</a> to export all saved links and their metadata in <a href="https://jsonlines.org/">JSON Lines format</a>.
This is useful to create data snapshots that can be restored later.

<pre>{{`$ curl -L go/.export
{"Short":"go","Long":"http://go","Created":"2022-05-31T13:04:44.741457796-07:00","LastEdit":"2022-05-31T13:04:44.741457796-07:00","Owner":"amelie@example.com","Clicks":1}
<pre>$ curl -L {{go}}/.export
{{`{"Short":"go","Long":"http://go","Created":"2022-05-31T13:04:44.741457796-07:00","LastEdit":"2022-05-31T13:04:44.741457796-07:00","Owner":"amelie@example.com","Clicks":1}
{"Short":"slack","Long":"https://company.slack.com/{{if .Path}}channels/{{PathEscape .Path}}{{end}}","Created":"2022-06-17T18:05:43.562948451Z","LastEdit":"2022-06-17T18:06:35.811398Z","Owner":"amelie@example.com","Clicks":4}`}}
</pre>

<p>
Create a new link by sending a POST request with a <code>short</code> and <code>long</code> value:

<pre>{{`$ curl -L -H Sec-Golink:1 -d short=cs -d long=https://cs.github.com/ go
{"Short":"cs","Long":"https://cs.github.com/","Created":"2022-06-03T22:15:29.993978392Z","LastEdit":"2022-06-03T22:15:29.993978392Z","Owner":"amelie@example.com"}`}}
<pre>$ curl -L -H Sec-Golink:1 -d short=cs -d long=https://cs.github.com/ {{go}}
{{`{"Short":"cs","Long":"https://cs.github.com/","Created":"2022-06-03T22:15:29.993978392Z","LastEdit":"2022-06-03T22:15:29.993978392Z","Owner":"amelie@example.com"}`}}
</pre>

</article>
Expand Down
6 changes: 3 additions & 3 deletions tmpl/home.html
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,12 @@
<h2 class="text-xl font-bold pb-2">Create a new link</h2>

{{ with .Long }}
<p class="">Did you mean <a class="text-blue-600 hover:underline" href="{{.}}">{{.}}</a> ? Create a go link for it now:</p>
<p class="">Did you mean <a class="text-blue-600 hover:underline" href="{{.}}">{{.}}</a> ? Create a {{go}} link for it now:</p>
{{ end }}
<form method="POST" action="/" class="flex flex-wrap">
<input type="hidden" name="xsrf" value="{{ .XSRF }}" />
<div class="flex">
<label for=short class="flex my-2 px-2 items-center bg-gray-100 border border-r-0 border-gray-300 rounded-l-md text-gray-700">http://go/</label>
<label for=short class="flex my-2 px-2 items-center bg-gray-100 border border-r-0 border-gray-300 rounded-l-md text-gray-700">http://{{go}}/</label>
<input id=short name=short required type=text size=15 placeholder="shortname" value="{{.Short}}" pattern="\w[\w\-\.]*" title="Must start with letter or number; may contain letters, numbers, dashes, and periods."
class="p-2 my-2 rounded-r-md border-gray-300 placeholder:text-gray-400">
<span class="flex m-2 items-center">&rarr;</span>
Expand All @@ -29,7 +29,7 @@ <h2 class="text-xl font-bold pt-6 pb-2">Popular Links</h2>
{{range .Clicks}}
<tr class="hover:bg-gray-100 group border-b border-gray-200">
<td class="flex">
<a class="block flex-1 p-2 pr-4 hover:text-blue-500 hover:underline" href="/{{.Short}}">go/{{.Short}}</a>
<a class="block flex-1 p-2 pr-4 hover:text-blue-500 hover:underline" href="/{{.Short}}">{{go}}/{{.Short}}</a>
<a class="flex items-center px-2 invisible group-hover:visible" title="Link Details" href="/.detail/{{.Short}}">
<svg class="hover:fill-blue-500" xmlns="http://www.w3.org/2000/svg" height="1.3em" viewBox="0 0 24 24" width="1.3em" fill="#000000" stroke-width="2"><path d="M0 0h24v24H0V0z" fill="none"/><path d="M11 7h2v2h-2zm0 4h2v6h-2zm1-9C6.48 2 2 6.48 2 12s4.48 10 10 10 10-4.48 10-10S17.52 2 12 2zm0 18c-4.41 0-8-3.59-8-8s3.59-8 8-8 8 3.59 8 8-3.59 8-8 8z"/></svg>
</a>
Expand Down
8 changes: 4 additions & 4 deletions tmpl/opensearch.xml
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
<OpenSearchDescription xmlns="http://a9.com/-/spec/opensearch/1.1/" xmlns:moz="http://www.mozilla.org/2006/browser/search/">
<ShortName>{{.Hostname}}</ShortName>
<ShortName>{{go}}</ShortName>
<Description>Private shortlinks on your tailnet</Description>
<InputEncoding>UTF-8</InputEncoding>
<Image width="16" height="16" type="image/png">http://{{.Hostname}}/.static/favicon.png</Image>
<Url type="text/html" method="get" template="http://{{.Hostname}}/{searchTerms}"/>
<moz:SearchForm>http://{{.Hostname}}/</moz:SearchForm>
<Image width="16" height="16" type="image/png">http://{{go}}/.static/favicon.png</Image>
<Url type="text/html" method="get" template="http://{{go}}/{searchTerms}"/>
<moz:SearchForm>http://{{go}}/</moz:SearchForm>
</OpenSearchDescription>
2 changes: 1 addition & 1 deletion tmpl/success.html
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
{{ define "main" }}
<h2 class="text-xl font-bold pb-2">Success</h2>

<p><a class="text-blue-600 hover:underline" href="/{{.Short}}">go/{{.Short}}</a> has been saved.</p>
<p><a class="text-blue-600 hover:underline" href="/{{.Short}}">{{go}}/{{.Short}}</a> has been saved.</p>
{{ end }}

0 comments on commit a83ef33

Please sign in to comment.