Skip to content

Commit

Permalink
Shankiyani/initial popup (#181)
Browse files Browse the repository at this point in the history
* initial go template and styling

* first pass at the server

* send form labels to template

* add reset button

* remove print statement in server file, label todos

* Update assets/templates/index.gohtml

Co-authored-by: Seth Vargo <seth@sethvargo.com>
Signed-off-by: Shan Kiyani <shankiyani@google.com>

* Update assets/templates/index.gohtml

Co-authored-by: Seth Vargo <seth@sethvargo.com>
Signed-off-by: Shan Kiyani <shankiyani@google.com>

* Update assets/templates/index.gohtml

Co-authored-by: Seth Vargo <seth@sethvargo.com>
Signed-off-by: Shan Kiyani <shankiyani@google.com>

* rename template file, format css file

* set hidden field values via script tag

* Add success page html, used for postMessage on page load

* redo the template, dont use floats in css

* run gofumpt and set timeouts for http server

* Update pkg/ui/server.go

Co-authored-by: Seth Vargo <seth@sethvargo.com>
Signed-off-by: Shan Kiyani <shan.a.raja@gmail.com>

* Update pkg/ui/server.go

Co-authored-by: Seth Vargo <seth@sethvargo.com>
Signed-off-by: Shan Kiyani <shan.a.raja@gmail.com>

* clean up css

* alert user when context is missing

* add additional meta tags, format all files

* turn off detect indentation, set to 2 spaces

* Address comments, add config.go

* add favicons

* format reset.css and remove unused struct

* add a forbidden page

* Support allowlist env variable

* Add some tests for validation methods

* Update pkg/ui/server.go

Co-authored-by: Seth Vargo <seth@sethvargo.com>
Signed-off-by: Shan Kiyani <shan.a.raja@gmail.com>

* add new line to reset.css

rename main script to success to match html file name
rename windowname attribute to window-name
move script tag inside body for both html files
proper indentation on xml and json
add copyright headers
use querySelector over addEventListener
use window for event listener
shorthand err check on config
make regex pattern a global variable

* add testing for config file

* add local ip check, remove helper handler, refactor tests

* add _head.html.tmpl, rename main template file for popup

* add Validate to cfg interface

use logger instead of log
in tests want and got or sufficient
remove .flex-outer in css

* refactor, inspired by EN service

* resolve bugs from manual testing

* run the linter

* add basic testing for the popup handler

* address comments, add a readme

---------

Signed-off-by: Shan Kiyani <shankiyani@google.com>
Signed-off-by: Shan Kiyani <shan.a.raja@gmail.com>
Co-authored-by: Seth Vargo <seth@sethvargo.com>
  • Loading branch information
2 people authored and verbanicm committed Feb 21, 2023
1 parent 9509c32 commit 837f1bc
Show file tree
Hide file tree
Showing 34 changed files with 1,965 additions and 3 deletions.
5 changes: 3 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -26,9 +26,10 @@ JVS consists of the following components:
* [Public Key API](./cmd/public-key):
[JWKs](https://auth0.com/docs/secure/tokens/json-web-tokens/json-web-key-sets).
* [CLI Tool](./cmd/jvsctl)
* [UI](./cmd/ui)

See manuals for [JVS APIs usage](./docs/jvs-apis.md) and
[JVS CLI Tool Usage](./docs/cli-tool.md)
See manuals for [JVS APIs usage](./docs/jvs-apis.md),
[JVS CLI Tool Usage](./docs/cli-tool.md), and [JVS UI usage](./docs/jvs-ui.md)

**TODO(#115):** add a simple diagram to describe the user experience flow of
enabling JVS in Lumberjack.
52 changes: 52 additions & 0 deletions assets/assets.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
// Copyright 2023 The Authors (see AUTHORS file)
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

// Package assets defines the templates and embedded filesystems.
package assets

import (
"embed"
"io/fs"
"os"

"github.com/abcxyz/jvs/internal/project"
)

//go:embed server server/**/* server/**/**/*
var _serverFS embed.FS

// This gets around an inconsistency where the embed is rooted at server/, but
// the os.DirFS is rooted after server/.
var serverFS, _ = fs.Sub(_serverFS, "server")

// ServerFS returns the file system for the server assets.
func ServerFS() fs.FS {
if project.DevMode() {
return os.DirFS(project.Root("assets", "server"))
}

return serverFS
}

var serverStaticFS, _ = fs.Sub(serverFS, "static")

// ServerStaticFS returns the file system for the server static assets, rooted
// at static/.
func ServerStaticFS() fs.FS {
if project.DevMode() {
return os.DirFS(project.Root("assets", "server", "static"))
}

return serverStaticFS
}
13 changes: 13 additions & 0 deletions assets/server/400.html.tmpl
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
<!DOCTYPE html>
<html lang="en">

<head>
{{ template "head" . }}
</head>

<body>
<h1>{{ .PageTitle }}</h1>
<p style="font-family:monospace">{{ .Message }}</p>
</body>

</html>
32 changes: 32 additions & 0 deletions assets/server/head.html.tmpl
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
{{ define "head" }}
<meta charset="utf-8">
<meta name="viewport"
content="width=device-width, initial-scale=1.0, minimum-scale=1.0, maximum-scale=1.0, user-scalable=no, shrink-to-fit=no, viewport-fit=cover, target-densityDpi=device-dpi">
<meta name="robots" content="noindex, nofollow, noarchive">
<meta property="og:description" content="{{ .Description }}" />
<meta name="description" content="{{ .Description }}">
<meta property="og:title" content="{{ .PageTitle }}" />
<meta name="apple-mobile-web-app-capable" property="apple-mobile-web-app-capable" content="yes">
<meta name="apple-mobile-web-app-status-bar-style" property="apple-mobile-web-app-status-bar-style"
media="(prefers-color-scheme: light)" content="white">
<meta name="apple-mobile-web-app-status-bar-style" property="apple-mobile-web-app-status-bar-style"
media="(prefers-color-scheme: dark)" content="black">
<meta name="theme-color" media="(prefers-color-scheme: light)" content="white">
<meta name="theme-color" media="(prefers-color-scheme: dark)" content="black">
<link rel="icon" type="image/png" sizes="192x192" href="/static/android-chrome-192x192.png">
<link rel="icon" type="image/png" sizes="512x512" href="/static/android-chrome-512x512.png">
<link rel="apple-touch-icon" sizes="180x180" href="/static/apple-touch-icon.png">
<link rel="icon" type="image/png" sizes="32x32" href="/static/favicon-32x32.png">
<link rel="icon" type="image/png" sizes="16x16" href="/static/favicon-16x16.png">
<link rel="manifest" href="/static/site.webmanifest">
<link rel="mask-icon" href="/static/safari-pinned-tab.svg" color="#5bbad5">
<meta name="msapplication-TileColor" content="#da532c">
<meta name="theme-color" content="#ffffff">
<meta name="msapplication-config" content="/static/browserconfig.xml" />
<meta name="msapplication-TileColor" content="#c7b3d2">
<meta name="msapplication-TileImage" content="mstile-144x144.png">
<title>{{ .PageTitle }}</title>

{{ cssIncludeTag }}

{{ end }}
86 changes: 86 additions & 0 deletions assets/server/popup.html.tmpl
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
<!DOCTYPE html>
<html lang="en">

<head>
{{ template "head" . }}
{{ jsPopupIncludeTag }}
</head>

<body>
{{ $context := . }}
<div class="container">
<h1 class="title">{{ .PageTitle }}</h1>
<form action="/popup" method="post">
<ul class="flex-outer">

<!-- Username -->
<li class="content-row">
<label class="content-label" for="username">Username</label>
<label class="content-data" for="username">TODO username</label>
</li>

<!-- Category row -->
<li class="content-row">
<label class="content-label" for="category">Category</label>
<select class="content-select" id="category" name="category">
{{ range $index, $element := .Content.Categories }}
{{ if eq $element.Key $context.Category }}
<option value="{{ $element.Key }}" selected="selected">{{ $element.Text }}</option>
{{ else }}
<option value="{{ $element.Key }}">{{ $element.Text }}</option>
{{ end }}
{{ end }}
</select>
</li>
{{ if .Errors.Category }}
<li class="content-row">
<label class="content-error" style="color:red;">{{ .Errors.Category }}</label>
</li>
{{ end }}

<!-- Reason row -->
<li class="content-row">
<label class="content-label" for="reason">Reason</label>
<input class="content-input" type="text" id="reason" name="reason" placeholder="i.e. issue/xxxxx">
</li>
{{ if .Errors.Reason }}
<li class="content-row">
<label class="content-error" style="color:red;">{{ .Errors.Reason }}</label>
</li>
{{ end }}

<!-- TTL row -->
<li class="content-row">
<label class="content-label" for="ttl">TTL</label>
<select class="content-select" id="ttl" name="ttl">
{{ range $index, $element := .Content.TTLs }}
{{ if eq $element.Key $context.TTL }}
<option value="{{ $element.Key }}" selected="selected">{{ $element.Text }}</option>
{{ else }}
<option value="{{ $element.Key }}">{{ $element.Text }}</option>
{{ end }}
{{ end }}
</select>
</li>
{{ if .Errors.TTL }}
<li class="content-row">
<label class="content-error" style="color:red;">{{ .Errors.TTL }}</label>
</li>
{{ end }}

<!-- Action buttons -->
<div class="form-btns">
<input class="secondary-btn" type="reset" value="Reset">
<input class="primary-btn" type="submit" value="Submit">
</div>
</ul>

<!-- Hidden fields -->
<input type="hidden" id="origin" name="origin" value="{{ .Origin }}">
<input type="hidden" id="windowname" name="windowname" value="{{ .WindowName }}">

</form>
</div>
</body>

</html>
Binary file added assets/server/static/android-chrome-192x192.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added assets/server/static/android-chrome-512x512.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added assets/server/static/apple-touch-icon.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
9 changes: 9 additions & 0 deletions assets/server/static/browserconfig.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
<?xml version="1.0" encoding="utf-8"?>
<browserconfig>
<msapplication>
<tile>
<square150x150logo src="/mstile-150x150.png"/>
<TileColor>#da532c</TileColor>
</tile>
</msapplication>
</browserconfig>
30 changes: 30 additions & 0 deletions assets/server/static/css/reset.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
html {
box-sizing: border-box;
font-size: 16px;
}

*,
*::before,
*::after {
box-sizing: inherit;
}

body,
p,
ol,
ul {
margin: 0;
font-weight: normal;
padding: 3.125rem 0;
}

ol,
ul {
list-style: none;
}

img {
max-width: 100%;
height: auto;
}

66 changes: 66 additions & 0 deletions assets/server/static/css/style.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
.container {
width: 80%;
max-width: 75rem;
margin: 0 auto;
}

.title {
text-align: center;
}

.flex-outer {
list-style-type: none;
padding: 0;
max-width: 50rem;
margin: 0 auto;
}

.content-row {
display: flex;
flex-wrap: wrap;
align-items: center;
}

.flex-outer > .content-row:not(:last-child) {
margin-bottom: 1.25rem;
}

.content-label {
padding: 0.5rem;
font-weight: 300;
letter-spacing: 0.1rem;
text-transform: uppercase;
flex: 1 0 7.5rem;
max-width: 13.75rem;
}

.form-btns * {
margin-left: 1rem;
padding: 0.5rem 1rem;
border: none;
background: #333;
color: #f2f2f2;
text-transform: uppercase;
letter-spacing: 0.1rem;
border-radius: 0.125rem;
}

.flex-outer > .content-row > .content-label + * {
flex: 1 0 13.75rem;
}

.content-row .content-error {
font-weight: 300;
flex: 1 0 7.5rem;
max-width: 13.75rem;
}

.flex-outer > .content-row .content-select,
.flex-outer > .content-row .content-input {
padding: 1rem;
}

.form-btns {
display: flex;
justify-content: flex-end;
}
Binary file added assets/server/static/favicon-16x16.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added assets/server/static/favicon-32x32.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added assets/server/static/favicon.ico
Binary file not shown.
39 changes: 39 additions & 0 deletions assets/server/static/js/popup/main.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
// Copyright 2023 The Authors (see AUTHORS file)
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

window.addEventListener("DOMContentLoaded", async () => {
const originElement = document.getElementById("origin");
const windowElement = document.getElementById("windowname");

// leverage the URL parameter provided from the request and set it to the target origin
const encodedUriComponent = new URLSearchParams(window.location.search).get("origin");
if (!encodedUriComponent && !originElement) {
alert("An origin URL parameter must be provided.")
window.close();
return;
}

if (encodedUriComponent) {
const targetOrigin = decodeURIComponent(encodedUriComponent);
if (!targetOrigin) {
alert("Decoded URL parameter is invalid.")
window.close();
return;
}

// set values for the following hidden input elements, will be persisted to the next page
originElement.value = targetOrigin;
windowElement.value = window.name;
}
}, true);
39 changes: 39 additions & 0 deletions assets/server/static/js/success/main.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
// Copyright 2023 The Authors (see AUTHORS file)
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

const scriptTag = document.querySelector("#success");
const targetOrigin = scriptTag.getAttribute("data-origin");
const windowName = scriptTag.getAttribute("data-window-name");
const token = scriptTag.getAttribute("data-token");
if (!targetOrigin) {
alert("You must pass a target origin from your application to successfully retrieve a token.")
window.close()
} else if (!windowName) {
alert("You must pass a window name from your application to successfully retrieve a token.")
} else if (!token) {
alert("Something went wrong, unable to retrieve a token.")
} else {
window.opener.postMessage(
JSON.stringify({
// notify the requestor of the window name that was provided,
// client should check this as a sanity check
source: windowName,
payload: {
token,
},
}),
targetOrigin
);
}
window.close();
Binary file added assets/server/static/mstile-144x144.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading

0 comments on commit 837f1bc

Please sign in to comment.