Auth: Add page to change password.
Configure launcher as a default return to address.
Use standard X-Forwarded-User instead of custom X-User header.
Add X-Forwarded-UserId header holding user unique identificator.
Change-Id: Ib2e6329ba9fb91d2cc9a86b0c5fc78898769e3b8
diff --git a/core/installer/cmd/launcher.go b/core/installer/cmd/launcher.go
index 85e811f..71decb6 100644
--- a/core/installer/cmd/launcher.go
+++ b/core/installer/cmd/launcher.go
@@ -3,6 +3,7 @@
import (
"fmt"
"log"
+ "net/url"
"os"
"github.com/giolekva/pcloud/core/installer"
@@ -14,6 +15,7 @@
)
var launcherFlags struct {
+ // TODO(gio): rename to auth-base-addr
logoutURL string
port int
repoAddr string
@@ -78,9 +80,13 @@
if err != nil {
return err
}
+ authBaseAddr, err := url.Parse(launcherFlags.logoutURL)
+ if err != nil {
+ return err
+ }
s, err := welcome.NewLauncherServer(
launcherFlags.port,
- launcherFlags.logoutURL,
+ fmt.Sprintf("https://%s", authBaseAddr.Host),
&welcome.AppManagerDirectory{AppManager: appManager},
)
if err != nil {
diff --git a/core/installer/cmd/welcome.go b/core/installer/cmd/welcome.go
index 30ed48f..d754ad3 100644
--- a/core/installer/cmd/welcome.go
+++ b/core/installer/cmd/welcome.go
@@ -88,7 +88,7 @@
if err != nil {
return err
}
- s := welcome.NewServer(
+ s, err := welcome.NewServer(
welcomeFlags.port,
repoIO,
nsCreator,
@@ -97,6 +97,9 @@
welcomeFlags.loginAddr,
welcomeFlags.membershipsAddr,
)
+ if err != nil {
+ return err
+ }
s.Start()
return nil
}
diff --git a/core/installer/values-tmpl/core-auth.cue b/core/installer/values-tmpl/core-auth.cue
index d535c97..b3146f8 100644
--- a/core/installer/values-tmpl/core-auth.cue
+++ b/core/installer/values-tmpl/core-auth.cue
@@ -428,6 +428,7 @@
domain: input.network.domain
hydra: "hydra-admin.\(global.namespacePrefix)core-auth.svc.cluster.local"
enableRegistration: false
+ defaultReturnTo: "https://launcher.\(global.domain)"
image: {
repository: images.ui.fullName
tag: images.ui.tag
diff --git a/core/installer/welcome/create-account.html b/core/installer/welcome/create-account.html
deleted file mode 100644
index cb9351e..0000000
--- a/core/installer/welcome/create-account.html
+++ /dev/null
@@ -1,48 +0,0 @@
-<!DOCTYPE html>
-<html lang="en" data-theme="light">
-<head>
- <link rel="stylesheet" href="/stat/pico.2.0.6.min.css">
- <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/hack-font/3.3.0/web/hack.min.css">
- <link rel="stylesheet" href="/stat/welcome.css?v=0.0.1">
- <meta charset="utf-8" />
- <meta name="viewport" content="width=device-width, initial-scale=1" />
-</head>
-<body>
- <main class="container">
- <div class="form-container">
- <div class="logo">
- <span>do</span><span>do:</span>
- </div>
- <form action="" method="POST">
- <label>
- username
- <input type="text" name="username" aria-label="Username" value="{{ .Data.Username }}" aria-invalid="{{ if .UsernameErrors }}true{{ else }}undefined{{ end }}" required/>
- </label>
- {{ if .UsernameErrors }}
- {{ range .UsernameErrors }}
- <small class="error-message" aria-live="assertive">
- {{ . }}
- </small>
- {{ end }}
- {{ end }}
- <label>
- password
- <input type="password" name="password" aria-label="Password" value="{{ .Data.Password }}" aria-invalid="{{ if .PasswordErrors }}true{{ else }}undefined{{ end }}" required/>
- </label>
- {{ if .PasswordErrors }}
- {{ range .PasswordErrors }}
- <small class="error-message" aria-live="assertive">
- {{ . }}
- </small>
- {{ end }}
- {{ end }}
- <label>
- secret token
- <input type="text" name="secret-token" aria-label="Secret Token" value="{{ .Data.SecretToken }}" required/>
- </label>
- <button type="submit">create account</button>
- </form>
- </div>
- </main>
-</body>
-</html>
diff --git a/core/installer/welcome/dodo_app.go b/core/installer/welcome/dodo_app.go
index d71bf83..256007e 100644
--- a/core/installer/welcome/dodo_app.go
+++ b/core/installer/welcome/dodo_app.go
@@ -316,7 +316,7 @@
}
func (ug internalUserGetter) Get(r *http.Request) string {
- return r.Header.Get("X-User")
+ return r.Header.Get("X-Forwarded-User")
}
func (ug internalUserGetter) Encode(w http.ResponseWriter, user string) error {
diff --git a/core/installer/welcome/launcher-tmpl/launcher.html b/core/installer/welcome/launcher-tmpl/launcher.html
index e75a616..76f7dd5 100644
--- a/core/installer/welcome/launcher-tmpl/launcher.html
+++ b/core/installer/welcome/launcher-tmpl/launcher.html
@@ -5,7 +5,7 @@
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>dodo: Launcher</title>
<link rel="stylesheet" type="text/css" href="/stat/pico.2.0.6.min.css">
- <link rel="stylesheet" type="text/css" href="/stat/launcher.css?v=0.0.20">
+ <link rel="stylesheet" type="text/css" href="/stat/launcher.css?v=0.0.21">
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/hack-font/3.3.0/web/hack.min.css">
</head>
<body class="container-fluid">
@@ -15,7 +15,8 @@
<p id="user-initial">{{ GetUserInitials .LoggedInUsername }}</p>
<div class="tooltip-user" id="tooltip-user">
<p>{{ .LoggedInUsername }}</p>
- <a href="{{ .LogoutURL }}" role="button" id="logout-button">Log Out</a>
+ <a href="{{ .AuthBaseAddr }}/change-password" role="button" class="profile-button" target="_blank">change password</a>
+ <a href="{{ .AuthBaseAddr }}/logout" role="button" class="profile-button">log out</a>
</div>
</div>
</div>
diff --git a/core/installer/welcome/launcher.go b/core/installer/welcome/launcher.go
index 88047d8..bab9163 100644
--- a/core/installer/welcome/launcher.go
+++ b/core/installer/welcome/launcher.go
@@ -80,14 +80,14 @@
type LauncherServer struct {
port int
- logoutURL string
+ authBaseAddr string
appDirectory AppDirectory
homeTmpl *template.Template
}
func NewLauncherServer(
port int,
- logoutURL string,
+ authBaseAddr string,
appDirectory AppDirectory,
) (*LauncherServer, error) {
tmpl, err := indexHTML.ReadFile("launcher-tmpl/launcher.html")
@@ -104,7 +104,7 @@
}
return &LauncherServer{
port,
- logoutURL,
+ authBaseAddr,
appDirectory,
t,
}, nil
@@ -128,7 +128,7 @@
}
func getLoggedInUser(r *http.Request) (string, error) {
- if user := r.Header.Get("X-User"); user != "" {
+ if user := r.Header.Get("X-Forwarded-User"); user != "" {
return user, nil
} else {
return "", fmt.Errorf("unauthenticated")
@@ -145,7 +145,7 @@
type homeHandlerData struct {
LoggedInUsername string
AllAppsInfo []AppLauncherInfo
- LogoutURL string
+ AuthBaseAddr string
}
func (s *LauncherServer) homeHandler(w http.ResponseWriter, r *http.Request) {
@@ -161,7 +161,7 @@
data := homeHandlerData{
LoggedInUsername: loggedInUsername,
AllAppsInfo: allAppsInfo,
- LogoutURL: s.logoutURL,
+ AuthBaseAddr: s.authBaseAddr,
}
if err := s.homeTmpl.Execute(w, data); err != nil {
http.Error(w, err.Error(), http.StatusInternalServerError)
diff --git a/core/installer/welcome/stat/hi.txt b/core/installer/welcome/stat/hi.txt
deleted file mode 100644
index 45b983b..0000000
--- a/core/installer/welcome/stat/hi.txt
+++ /dev/null
@@ -1 +0,0 @@
-hi
diff --git a/core/installer/welcome/stat/launcher.css b/core/installer/welcome/stat/launcher.css
index c3a49bf..636c0c0 100644
--- a/core/installer/welcome/stat/launcher.css
+++ b/core/installer/welcome/stat/launcher.css
@@ -338,9 +338,8 @@
.tooltip-user {
position: absolute;
- top: 38.7px;
+ top: 0px;
left: 80px;
- transform: translateY(-50%);
width: 234px;
background-color: var(--bodyBg);
padding: 5px;
@@ -354,7 +353,7 @@
box-shadow: 2px 2px 5px var(--bodyBg);
}
-#logout-button {
+.profile-button {
margin-top: 5px !important;
padding: 0 !important;
border: 0 !important;
diff --git a/core/installer/welcome/create-account-success.html b/core/installer/welcome/welcome-tmpl/base.html
similarity index 73%
rename from core/installer/welcome/create-account-success.html
rename to core/installer/welcome/welcome-tmpl/base.html
index 86563c6..44861de 100644
--- a/core/installer/welcome/create-account-success.html
+++ b/core/installer/welcome/welcome-tmpl/base.html
@@ -10,10 +10,7 @@
</head>
<body>
<main class="container">
- <div>
- <p>Your account has been successfully created.</p>
- <p>Click <a href="{{ .LoginAddr }}">here</a> to open up the Launcher.</p>
- </div>
+ {{ block "content" . }}{{ end }}
</main>
</body>
</html>
diff --git a/core/installer/welcome/welcome-tmpl/create-account-success.html b/core/installer/welcome/welcome-tmpl/create-account-success.html
new file mode 100644
index 0000000..8de510e
--- /dev/null
+++ b/core/installer/welcome/welcome-tmpl/create-account-success.html
@@ -0,0 +1,6 @@
+{{ define "content" }}
+<div>
+ <p>Your account has been successfully created.</p>
+ <p>Click <a href="{{ .LoginAddr }}">here</a> to open up the Launcher.</p>
+</div>
+{{ end }}
diff --git a/core/installer/welcome/welcome-tmpl/create-account.html b/core/installer/welcome/welcome-tmpl/create-account.html
new file mode 100644
index 0000000..ecd547f
--- /dev/null
+++ b/core/installer/welcome/welcome-tmpl/create-account.html
@@ -0,0 +1,36 @@
+{{ define "content" }}
+<div class="form-container">
+ <div class="logo">
+ <span>do</span><span>do:</span>
+ </div>
+ <form action="" method="POST">
+ <label>
+ username
+ <input type="text" name="username" aria-label="Username" value="{{ .Data.Username }}" aria-invalid="{{ if .UsernameErrors }}true{{ else }}undefined{{ end }}" required/>
+ </label>
+ {{ if .UsernameErrors }}
+ {{ range .UsernameErrors }}
+ <small class="error-message" aria-live="assertive">
+ {{ . }}
+ </small>
+ {{ end }}
+ {{ end }}
+ <label>
+ password
+ <input type="password" name="password" aria-label="Password" value="{{ .Data.Password }}" aria-invalid="{{ if .PasswordErrors }}true{{ else }}undefined{{ end }}" required/>
+ </label>
+ {{ if .PasswordErrors }}
+ {{ range .PasswordErrors }}
+ <small class="error-message" aria-live="assertive">
+ {{ . }}
+ </small>
+ {{ end }}
+ {{ end }}
+ <label>
+ secret token
+ <input type="text" name="secret-token" aria-label="Secret Token" value="{{ .Data.SecretToken }}" required/>
+ </label>
+ <button type="submit">create account</button>
+ </form>
+</div>
+{{ end }}
diff --git a/core/installer/welcome/welcome.go b/core/installer/welcome/welcome.go
index b6436c7..7aa6d3a 100644
--- a/core/installer/welcome/welcome.go
+++ b/core/installer/welcome/welcome.go
@@ -18,11 +18,8 @@
"github.com/giolekva/pcloud/core/installer/soft"
)
-//go:embed create-account.html
-var indexHtml []byte
-
-//go:embed create-account-success.html
-var successHtml []byte
+//go:embed welcome-tmpl/*
+var welcomeTmpls embed.FS
//go:embed static/*
var staticAssets embed.FS
@@ -30,6 +27,34 @@
//go:embed stat/*
var statAssets embed.FS
+type welcomeTmplts struct {
+ createAccount *template.Template
+ createAccountSuccess *template.Template
+}
+
+func parseTemplatesWelcome(fs embed.FS) (welcomeTmplts, error) {
+ base, err := template.New("base.html").ParseFS(fs, "welcome-tmpl/base.html")
+ if err != nil {
+ return welcomeTmplts{}, err
+ }
+ parse := func(path string) (*template.Template, error) {
+ if b, err := base.Clone(); err != nil {
+ return nil, err
+ } else {
+ return b.ParseFS(fs, path)
+ }
+ }
+ createAccount, err := parse("welcome-tmpl/create-account.html")
+ if err != nil {
+ return welcomeTmplts{}, err
+ }
+ createAccountSuccess, err := parse("welcome-tmpl/create-account-success.html")
+ if err != nil {
+ return welcomeTmplts{}, err
+ }
+ return welcomeTmplts{createAccount, createAccountSuccess}, nil
+}
+
type Server struct {
port int
repo soft.RepoIO
@@ -38,6 +63,7 @@
createAccountAddr string
loginAddr string
membershipsAddr string
+ tmpl welcomeTmplts
}
func NewServer(
@@ -48,7 +74,11 @@
createAccountAddr string,
loginAddr string,
membershipsAddr string,
-) *Server {
+) (*Server, error) {
+ tmplts, err := parseTemplatesWelcome(welcomeTmpls)
+ if err != nil {
+ return nil, err
+ }
return &Server{
port,
repo,
@@ -57,7 +87,8 @@
createAccountAddr,
loginAddr,
membershipsAddr,
- }
+ tmplts,
+ }, nil
}
func (s *Server) Start() {
@@ -70,7 +101,7 @@
}
func (s *Server) createAccountForm(w http.ResponseWriter, r *http.Request) {
- renderRegistrationForm(w, formData{})
+ s.renderRegistrationForm(w, formData{})
}
type formData struct {
@@ -79,6 +110,12 @@
Data createAccountReq
}
+type cpFormData struct {
+ UsernameErrors []string
+ PasswordErrors []string
+ Password string
+}
+
type createAccountReq struct {
Username string `json:"username,omitempty"`
Password string `json:"password,omitempty"`
@@ -132,30 +169,20 @@
return req, nil
}
-func renderRegistrationForm(w http.ResponseWriter, data formData) {
- tmpl, err := template.New("create-account").Parse(string(indexHtml))
- if err != nil {
- http.Error(w, err.Error(), http.StatusInternalServerError)
- return
- }
- if err := tmpl.Execute(w, data); err != nil {
+func (s *Server) renderRegistrationForm(w http.ResponseWriter, data formData) {
+ if err := s.tmpl.createAccount.Execute(w, data); err != nil {
http.Error(w, err.Error(), http.StatusInternalServerError)
return
}
}
-func renderRegistrationSuccess(w http.ResponseWriter, loginAddr string) {
+func (s *Server) renderRegistrationSuccess(w http.ResponseWriter, loginAddr string) {
data := struct {
LoginAddr string
}{
LoginAddr: loginAddr,
}
- tmpl, err := template.New("create-account-success").Parse(string(successHtml))
- if err != nil {
- http.Error(w, err.Error(), http.StatusInternalServerError)
- return
- }
- if err := tmpl.Execute(w, data); err != nil {
+ if err := s.tmpl.createAccountSuccess.Execute(w, data); err != nil {
http.Error(w, err.Error(), http.StatusInternalServerError)
return
}
@@ -200,7 +227,7 @@
passwordErrors = append(passwordErrors, err.Message)
}
}
- renderRegistrationForm(w, formData{
+ s.renderRegistrationForm(w, formData{
usernameErrors,
passwordErrors,
req,
@@ -212,7 +239,7 @@
http.Error(w, err.Error(), http.StatusInternalServerError)
return
}
- renderRegistrationSuccess(w, s.loginAddr)
+ s.renderRegistrationSuccess(w, s.loginAddr)
}
type firstAccount struct {