Skip to content
This repository has been archived by the owner on Jul 12, 2023. It is now read-only.

settings for enx #437

Merged
merged 1 commit into from
Sep 1, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
141 changes: 112 additions & 29 deletions cmd/server/assets/realm.html
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,21 @@ <h1>Realm settings</h1>
Find or edit the settings for <strong>{{$realm.Name}}</strong> below.
</p>

{{if not $realm.EnableENExpress}}
<div class="card mb-3">
<div class="card-header">
ENX - Exposure Notifications Express
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
ENX - Exposure Notifications Express
EN Express - Exposure Notifications Express

We say "EN Express" everywhere else except these titles.

</div>
<div class="card-body">
<form method="POST" action="/realm/settings/enable-express">
{{ .csrfField }}
<a href="#" class="btn btn-primary btn-block" data-confirm="Are you sure you want to enable EN Express? You should only do this if you have confirmed participation with Apple and Google." data-submit-form>Enable EN Express</a>
</form>
</div>
</div>
{{end}}


<form method="POST" action="/realm/settings/save">
{{ .csrfField }}

Expand Down Expand Up @@ -61,6 +76,7 @@ <h1>Realm settings</h1>
<div class="form-group row mb-0">
<label class="col-sm-3">Allowed tests:</label>
<div class="col-sm-9">
{{if not $realm.EnableENExpress}}
<div class="form-group mb-0">
<div class="form-check">
<input class="form-check-input" type="radio" name="allowedTestTypes" id="negative" value="{{$testTypes.negative}}"{{if eq $realm.AllowedTestTypes $testTypes.negative}} checked{{end}}/>
Expand All @@ -87,6 +103,7 @@ <h1>Realm settings</h1>
</label>
</div>
</div>
{{end}}

<div class="form-group">
<div class="form-check">
Expand All @@ -96,6 +113,10 @@ <h1>Realm settings</h1>
<small class="form-text text-muted">
Only permit confirmed positive tests from an official
testing source.
{{if $realm.EnableENExpress}} <br/>
You are enrolled in EN Express which only supports the sharing of
positive tests.
{{end}}
</small>
</label>
</div>
Expand All @@ -113,6 +134,9 @@ <h1>Realm settings</h1>
<div class="form-group row">
<label for="codeLength" class="col-sm-3">Short code characters:</label>
<div class="col-sm-9">
{{if $realm.EnableENExpress}}
<input class="form-control{{if $realm.ErrorsFor "codeLength"}} is-invalid{{end}}" name="codeLength" id="codeLength" type="text" value="{{$realm.CodeLength}}" readonly />
{{else}}
<select class="form-control{{if $realm.ErrorsFor "codeLength"}} is-invalid{{end}}" name="codeLength" id="codeLength">
{{range $cl := .shortCodeLengths}}
<option value="{{$cl}}" {{if (eq $cl $realm.CodeLength)}}selected{{end}}>{{$cl}}</option>
Expand All @@ -122,55 +146,68 @@ <h1>Realm settings</h1>
The short verification code is intended to be dictated over the phone to the
person and is <code>6</code>, <code>7</code>, or <code>8</code> digits in length.
</small>
{{end}}
</div>
</div>

<div class="form-group row">
<label for="codeLength" class="col-sm-3">Code expires after:</label>
<div class="col-sm-8">
<select class="form-control{{if $realm.ErrorsFor "CodeDurationSeconds"}} is-invalid{{end}}" name="codeDuration" id="codeDuration">
{{$current := $realm.GetCodeDurationMinutes}}
{{range $scm := .shortCodeMinutes}}
<option value="{{$scm}}" {{if (eq $scm $current)}}selected{{end}}>{{$scm}}</option>
{{end}}
</select>
<small class="form-text text-muted">
The short code can be valid from anywhere between <code>5</code> and <code>60</code>
minutes. If you are using SMS deeplinks, it is recommended to keep this duration
short and let the long code be valid for a longer period (up to <code>24</code> hours).
</small>
{{if $realm.EnableENExpress}}
<input class="form-control{{if $realm.ErrorsFor "CodeDurationSeconds"}} is-invalid{{end}}" name="codeDuration" id="codeDuration" type="text" value="{{$realm.GetCodeDurationMinutes}}" readonly />
{{else}}
<select class="form-control{{if $realm.ErrorsFor "CodeDurationSeconds"}} is-invalid{{end}}" name="codeDuration" id="codeDuration">
{{$current := $realm.GetCodeDurationMinutes}}
{{range $scm := .shortCodeMinutes}}
<option value="{{$scm}}" {{if (eq $scm $current)}}selected{{end}}>{{$scm}}</option>
{{end}}
</select>
<small class="form-text text-muted">
The short code can be valid from anywhere between <code>5</code> and <code>60</code>
minutes. If you are using SMS deeplinks, it is recommended to keep this duration
short and let the long code be valid for a longer period (up to <code>24</code> hours).
</small>
{{end}}
</div>
<div class="col-sm-1">minutes</div>
</div>

<div class="form-group row">
<label for="codeLength" class="col-sm-3">Long code characters:</label>
<div class="col-sm-9">
<select class="form-control{{if $realm.ErrorsFor "longCodeLength"}} is-invalid{{end}}" name="longCodeLength" id="longCodeLength">
{{range $cl := .longCodeLengths}}
<option value="{{$cl}}" {{if (eq $cl $realm.LongCodeLength)}}selected{{end}}>{{$cl}}</option>
{{end}}
</select>
{{if $realm.EnableENExpress}}
<input class="form-control{{if $realm.ErrorsFor "longCodeLength"}} is-invalid{{end}}" name="longCodeLength" id="longCodeLength" type="text" value="{{$realm.LongCodeLength}}" readonly />
{{else}}
<select class="form-control{{if $realm.ErrorsFor "longCodeLength"}} is-invalid{{end}}" name="longCodeLength" id="longCodeLength">
{{range $cl := .longCodeLengths}}
<option value="{{$cl}}" {{if (eq $cl $realm.LongCodeLength)}}selected{{end}}>{{$cl}}</option>
{{end}}
</select>
{{end}}
<small class="form-text text-muted">
The 'long' verification code is only delivered over SMS, is more complex with <code>12</code> -
The 'long' verification code is only delivered over SMS{{if not $realm.EnableENExpress}}, is more complex with <code>12</code> -
<code>16</code> alphanumeric characters, and is never shown to a human. It is recommended
to leave this at the default of <code>16</code> digits.
</small>
to leave this at the default of <code>16</code> digits{{end}}.
</small>
</div>
</div>

<div class="form-group row">
<label for="codeLength" class="col-sm-3">Long code expires after:</label>
<div class="col-sm-8">
<select class="form-control{{if $realm.ErrorsFor "LongCodeDurationSeconds"}} is-invalid{{end}}" name="longCodeDuration" id="longCodeDuration">
{{$current := $realm.GetLongCodeDurationHours}}
{{range $lch := .longCodeHours}}
<option value="{{$lch}}" {{if (eq $lch $current)}}selected{{end}}>{{$lch}}</option>
{{end}}
</select>
<small class="form-text text-muted">
The long code can be valid between <code>1</code> and <code>24</code> hours.
</small>
{{if $realm.EnableENExpress}}
<input class="form-control{{if $realm.ErrorsFor "LongCodeDurationSeconds"}} is-invalid{{end}}" name="longCodeDuration" id="longCodeDuration" type="text" value="{{$realm.GetLongCodeDurationHours}}" readonly />
{{else}}
<select class="form-control{{if $realm.ErrorsFor "LongCodeDurationSeconds"}} is-invalid{{end}}" name="longCodeDuration" id="longCodeDuration">
{{$current := $realm.GetLongCodeDurationHours}}
{{range $lch := .longCodeHours}}
<option value="{{$lch}}" {{if (eq $lch $current)}}selected{{end}}>{{$lch}}</option>
{{end}}
</select>
<small class="form-text text-muted">
The long code can be valid between <code>1</code> and <code>24</code> hours.
</small>
{{end}}
</div>
<div class="col-sm-1">hours</div>
</div>
Expand All @@ -188,7 +225,38 @@ <h1>Realm settings</h1>
The SMS message will be constructed based on the template you provide. The overall
length of of the SMS message should not exceede 160 characters, or your message will need to be split
in transit and may not be joined correctly. There are some special strings that you can use
to substitute items. Your SMS template <em>MUST</em> contain either the <code>[code]</code> or
to substitute items.
{{if $realm.EnableENExpress}}
Your SMS template <em>MUST</em> contain <code>[enslink]</code>.
<ul>
<li><code>[enslink]</code> Inserts the required EN Express link of: <code>ens://v?r=[region]&c=[longcode]</code></li>
<li><code>[longexpires]</code>The number of hours until the long code expires (just the number, no units).</li>
</ul>

Here is an example SMS template using EN Express.

<ul>
<li>
<p>Custom greeting before the EN Express link and showing expiration.
This is <code>145</code> characters when expanded.</p>
<p>
<samp class="text-dark">
State of Wonder Dept. of Health. Click to share anonymous data for exposure notifications [enslink] Expires in [longexpires] hours
</samp>
</p>
</li>
<li>
<p>This results in a SMS message that looks like:</p>
<p>
<samp class="text-dark">
State of Wonder Dept. of Health. Click to share anonymous data for exposure notifications ens://v?r=US-XX&c=12345678abcd1234 Expires in 24 hours
</samp>
</p>
</li>
</ul>

{{else}}
Your SMS template <em>MUST</em> contain either the <code>[code]</code> or
<code>[longcode]</code>.
<ul>
<li><code>[region]</code>The region setting (set on this page).</li>
Expand Down Expand Up @@ -222,6 +290,7 @@ <h1>Realm settings</h1>
</p>
</li>
</ul>
{{end}}
</small>
</div>
</div>
Expand Down Expand Up @@ -268,6 +337,20 @@ <h1>Realm settings</h1>
</div>
</div>
</form>

{{if $realm.EnableENExpress}}
<div class="card mb-3">
<div class="card-header">
ENX - Exposure Notifications Express
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
ENX - Exposure Notifications Express
EN Express - Exposure Notifications Express

</div>
<div class="card-body">
<form method="POST" action="/realm/settings/disable-express">
{{ .csrfField }}
<a href="#" class="btn btn-danger btn-block" data-confirm="Are you sure you want to disable EN Express? This could cause your iOS and Android integrations to stop working." data-submit-form>Disable EN Express</a>
</form>
</div>
</div>
{{end}}
</main>

{{template "scripts" .}}
Expand Down
2 changes: 2 additions & 0 deletions cmd/server/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -311,6 +311,8 @@ func realMain(ctx context.Context) error {
realmadminController := realmadmin.New(ctx, config, db, h)
realmSub.Handle("/settings", realmadminController.HandleIndex()).Methods("GET")
realmSub.Handle("/settings/save", realmadminController.HandleSave()).Methods("POST")
realmSub.Handle("/settings/enable-express", realmadminController.HandleEnableExpress()).Methods("POST")
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

These should technically be PATCH, but meh.

realmSub.Handle("/settings/disable-express", realmadminController.HandleDisableExpress()).Methods("POST")

realmKeysController, err := realmkeys.New(ctx, config, db, certificateSigner, h)
if err != nil {
Expand Down
108 changes: 108 additions & 0 deletions pkg/controller/realmadmin/express.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,108 @@
// Copyright 2020 Google LLC
//
// 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 realmadmin

import (
"net/http"

"github.com/google/exposure-notifications-verification-server/pkg/controller"
"github.com/google/exposure-notifications-verification-server/pkg/database"
)

func (c *Controller) HandleDisableExpress() http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
ctx := r.Context()

session := controller.SessionFromContext(ctx)
if session == nil {
controller.MissingSession(w, r, c.h)
return
}
flash := controller.Flash(session)

realm := controller.RealmFromContext(ctx)
if realm == nil {
controller.MissingRealm(w, r, c.h)
return
}

if !realm.EnableENExpress {
flash.Error("Realm is not currently enrolled in EN Express.")
c.renderShow(ctx, w, r, realm, nil)
return
}

defaultSettings := database.NewRealmWithDefaults("--")
realm.EnableENExpress = false
realm.SMSTextTemplate = defaultSettings.SMSTextTemplate
if err := c.db.SaveRealm(realm); err != nil {
flash.Error("Failed to disable EN Express: %v", err)

c.renderShow(ctx, w, r, realm, nil)
return
}

flash.Alert("Successfully disabled EN Express")
http.Redirect(w, r, "/realm/settings", http.StatusSeeOther)
})
}

func (c *Controller) HandleEnableExpress() http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
ctx := r.Context()

session := controller.SessionFromContext(ctx)
if session == nil {
controller.MissingSession(w, r, c.h)
return
}
flash := controller.Flash(session)

realm := controller.RealmFromContext(ctx)
if realm == nil {
controller.MissingRealm(w, r, c.h)
return
}

if realm.EnableENExpress {
flash.Error("Realm already has EN Express Enabled.")
c.renderShow(ctx, w, r, realm, nil)
return
}

// Enable EN Express by setting default settings.
enxSettings := database.NewRealmWithDefaults("--")
realm.EnableENExpress = true
realm.CodeLength = enxSettings.CodeLength
realm.CodeDuration = enxSettings.CodeDuration
realm.LongCodeLength = enxSettings.LongCodeLength
realm.LongCodeDuration = enxSettings.LongCodeDuration
realm.SMSTextTemplate = "This is your Exposure Notifications Verification code: [enslink] Expires in [longexpires] hours"
// Confirmed is the only allowed test type for EN Express.
realm.AllowedTestTypes = database.TestTypeConfirmed

if err := c.db.SaveRealm(realm); err != nil {
flash.Error("Failed to enable EN Express: %v", err)
// This will allow the user to correct other validation errors and then click "uprade" again.
realm.EnableENExpress = false
realm.SMSTextTemplate = enxSettings.SMSTextTemplate
c.renderShow(ctx, w, r, realm, nil)
return
}

flash.Alert("Successfully enabled EN Express!")
http.Redirect(w, r, "/realm/settings", http.StatusSeeOther)
})
}
12 changes: 1 addition & 11 deletions pkg/controller/realmadmin/index.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,6 @@ import (
"net/http"

"github.com/google/exposure-notifications-verification-server/pkg/controller"
"github.com/google/exposure-notifications-verification-server/pkg/database"
)

func (c *Controller) HandleIndex() http.Handler {
Expand All @@ -31,15 +30,6 @@ func (c *Controller) HandleIndex() http.Handler {
return
}

smsConfig, err := realm.SMSConfig(c.db)
if err != nil {
if !database.IsNotFound(err) {
controller.InternalError(w, r, c.h, err)
return
}
smsConfig = new(database.SMSConfig)
}

c.renderShow(ctx, w, realm, smsConfig)
c.renderShow(ctx, w, r, realm, nil)
})
}
Loading