Skip to content

Commit

Permalink
Resend Password Utility (#1169)
Browse files Browse the repository at this point in the history
* Resend Password Utility

* update email templates
  • Loading branch information
bbengfort authored May 22, 2024
1 parent c50bb60 commit 7526b28
Show file tree
Hide file tree
Showing 8 changed files with 151 additions and 34 deletions.
107 changes: 107 additions & 0 deletions cmd/reissuer/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -127,6 +127,33 @@ func main() {
},
},
},
{
Name: "password",
Usage: "view or resend the password for the latest certificate request",
Action: resendPassword,
Before: connectDB,
After: closeDB,
Flags: []cli.Flag{
&cli.StringFlag{
Name: "vasp",
Aliases: []string{"vasp-id", "v"},
Usage: "the VASP ID to send reissuance reminder notifications to",
Required: true,
},
&cli.BoolFlag{
Name: "yes",
Aliases: []string{"y"},
Usage: "skip the confirmation prompt and immediately send notifications",
Value: false,
},
&cli.BoolFlag{
Name: "show",
Aliases: []string{"s", "show-password"},
Usage: "show the password on the command line and exit without emailing the user",
Value: false,
},
},
},
{
Name: "proto",
Usage: "create an identity certificate protocol buffer from a certificate",
Expand Down Expand Up @@ -505,6 +532,86 @@ func reissueCerts(c *cli.Context) (err error) {
return nil
}

func resendPassword(c *cli.Context) (err error) {
var (
vasp *pb.VASP
vaspName string
certreqID string
pkcs12password []byte
sm *secrets.SecretManager
emailer *emails.EmailManager
whisperLink string
nsent int
)

ctx, cancel := utils.WithDeadline(context.Background())
defer cancel()

// Fetch and identify the VASP specified by the user
vaspID := c.String("vasp")
if vasp, err = db.RetrieveVASP(ctx, vaspID); err != nil {
return cli.Exit(fmt.Errorf("could not find VASP record %s: %s", vaspID, err), 1)
}

if vaspName, err = vasp.Name(); err != nil {
vaspName = vasp.CommonName
}

// Get the latest certificate request for the VASP
if certreqID, err = models.GetLatestCertReqID(vasp); err != nil {
return cli.Exit(fmt.Errorf("could not get latest certificate request ID for vasp %s: %s", vaspName, err), 1)
}

// Connect to the secrets store and fetch the PKCS12 password if it exists
if sm, err = secrets.New(conf.Secrets); err != nil {
return cli.Exit(fmt.Errorf("could not connect to secret manager: %s", err), 1)
}

if pkcs12password, err = sm.With(certreqID).GetLatestVersion(ctx, "password"); err != nil {
return cli.Exit(fmt.Errorf("could not retrieve pkcs12 password for vasp %s certificate request %s: %s", vaspName, certreqID, err), 1)
}

// If print password and exit, do that without user confirmation
if c.Bool("show") {
fmt.Printf("retrieved password for %s (certificate request %s)\n", vaspName, certreqID)
if !c.Bool("yes") {
if !askForConfirmation("show PKCS12 password on the command line?") {
return cli.Exit(fmt.Errorf("canceled by user"), 1)
}
}

// Print password and exit
fmt.Println(string(pkcs12password))
return nil
}

// Check with the user if we should continue with resending the password
fmt.Printf("resending password for %s (certificate request %s)\n", vaspName, certreqID)
if !c.Bool("yes") {
if !askForConfirmation("continue and resend PKCS12 password?") {
return cli.Exit(fmt.Errorf("canceled by user"), 1)
}
}

// Create the Whisper link for the provided PKCS12 password.
if whisperLink, err = whisper.CreateSecretLink(fmt.Sprintf(whisperPasswordTemplate, string(pkcs12password)), "", 3, weekFromNow()); err != nil {
return cli.Exit(err, 1)
}

// Create the email manager.
if emailer, err = emails.New(conf.Email); err != nil {
return cli.Exit(err, 1)
}

// Send the notification email that certificate reissuance is forthcoming and provide whisper link to the PKCS12 password.
if nsent, err = emailer.SendReissuanceStarted(vasp, whisperLink); err != nil {
return cli.Exit(err, 1)
}

fmt.Printf("successfully sent %d Whisper password notifications for PKCS12 password %q\n", nsent, pkcs12password)
return nil
}

func makeCertificateProto(c *cli.Context) (err error) {
var archive *trust.Serializer
if pkcs12password := c.String("pkcs12password"); pkcs12password != "" {
Expand Down
32 changes: 16 additions & 16 deletions pkg/gds/emails/bindata.go

Large diffs are not rendered by default.

13 changes: 9 additions & 4 deletions pkg/gds/emails/emails.go
Original file line number Diff line number Diff line change
Expand Up @@ -47,27 +47,32 @@ type VerifyContactData struct {
// VerifyContactURL composes the link to verify the contact from the context. If the
// link is not able to be composed, the function returns an empty string and logs an
// error because without the link the email is fairly useless.
func (d VerifyContactData) VerifyContactURL() string {
func (d VerifyContactData) VerifyContactURL() *url.URL {
var (
link *url.URL
err error
)
if d.BaseURL != "" {
if link, err = url.Parse(d.BaseURL); err != nil {
sentry.Error(nil).Err(err).Msg("could not include verify contact link in email, could not parse verify contact base url")
return ""
return nil
}
} else {
sentry.Error(nil).Msg("could not include verify contact link in email, no verify contact base url")
return ""
return nil
}

params := link.Query()
params.Set("vaspID", d.VID)
params.Set("token", d.Token)
params.Set("registered_directory", d.DirectoryID)
link.RawQuery = params.Encode()
return link.String()
return link
}

func (d VerifyContactData) VerifyContactURLUnencoded() template.HTML {
url := d.VerifyContactURL()
return template.HTML(url.String())
}

// ReviewRequestData to complete review request email templates.
Expand Down
3 changes: 1 addition & 2 deletions pkg/gds/emails/emails_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -120,8 +120,7 @@ func TestVerifyContactURL(t *testing.T) {
VID: "42",
BaseURL: "http://localhost:8080/verify",
}
link, err := url.Parse(data.VerifyContactURL())
require.NoError(t, err)
link := data.VerifyContactURL()
require.Equal(t, "http", link.Scheme)
require.Equal(t, "localhost:8080", link.Host)
require.Equal(t, "/verify", link.Path)
Expand Down
18 changes: 11 additions & 7 deletions pkg/gds/emails/templates/deliver_certs.html
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
<p>Hello {{ .Name }},</p>

<p>
Your TRISA network registration has been approved! Your organization has been
granted identity certificates validating your membership to other TRISA
Your TRISA network registration has been approved (or reapproved)! Your organization
has been granted identity certificates validating your membership to other TRISA
members via the TRISA Global Directory. Attached to this email are PKCS12
encrypted certificates so that you can implement the TRISA protocol using mTLS
with other network members to exchange Travel Rule compliance information.
Expand All @@ -20,13 +20,17 @@
</ul>

<p>
To decrypt your certificates, <em>you will need the PKCS12 password</em> that
you received when you first submitted your registration. To decrypt the
unzipped certificates on the command line, you can use <code>openssl</code> as
follows (you will be prompted to enter your password):
To decrypt your certificates, <em>you will need a PKCS12 password</em>. If this is
the first certificate you've received after registration, you'll need the PKCS12
password that was displayed during the registration process. If these are annually
re-issued certificates, you'll need the PCKS12 password that was emailed to you via a
one-time Whisper link preceding this email.
</p>

<pre>$ openssl pkcs12 -in INFILE.p12 -out OUTFILE.crt -nodes</pre>
<p>
To decrypt the unzipped certificates on the command line, you can use <code>openssl</code>
as described in <a href="https://trisa.dev/joining-trisa/pkcs12/index.html#accessing-and-saving-the-certificates">our documentation</a>.
<p>

<p>
For more information on integrating with the TRISA network, please see our
Expand Down
8 changes: 5 additions & 3 deletions pkg/gds/emails/templates/deliver_certs.txt
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
Hello {{ .Name }},

Your TRISA network registration has been approved! Your organization has been granted identity certificates validating your membership to other TRISA members via the TRISA Global Directory. Attached to this email are PKCS12 encrypted certificates so that you can implement the TRISA protocol using mTLS with other network members to exchange Travel Rule compliance information.
Your TRISA network registration has been approved (or reapproved)! Your organization has been granted identity certificates validating your membership to other TRISA members via the TRISA Global Directory. Attached to this email are PKCS12 encrypted certificates so that you can implement the TRISA protocol using mTLS with other network members to exchange Travel Rule compliance information.

The primary details of your directory entry are as follows:

Expand All @@ -11,9 +11,11 @@ Common Name: {{ .CommonName }}
Serial Number: {{ .SerialNumber }}
Endpoint: {{ .Endpoint }}

To decrypt your certificates, you will need the PKCS12 password that you received when you first submitted your registration. To decrypt the unzipped certificates on the command line, you can use openssl as follows (you will be prompted to enter your password):
To decrypt your certificates, you will need a PKCS12 password. If this is the first certificate you've recieved after registration, you'll need the PKCS12 password that was displayed during the registration process. If these are annually re-issued certificates, you'll need the PCKS12 password that was emailed to you via a one-time Whisper link preceding this email.

openssl pkcs12 -in INFILE.p12 -out OUTFILE.crt -nodes
To decrypt the unzipped certificates on the command line, you can use `openssl` as described in our documentation here:

https://trisa.dev/joining-trisa/pkcs12/index.html#accessing-and-saving-the-certificates

For more information on integrating with the TRISA network, please visit our documentation at https://trisa.dev/. If you have any questions, you may contact us at [email protected] or join us on our Slack channel trisa-workspace.slack.com. Please do not reply directly to this email.

Expand Down
2 changes: 1 addition & 1 deletion pkg/gds/emails/templates/verify_contact.html
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
If you cannot click on the link, please copy and paste the link below into your
browser address bar:</p>

<p><code>{{ .VerifyContactURL }}</code></p>
<p><code>{{ .VerifyContactURLUnencoded }}</code></p>

If you're having trouble verifying your contact email, please contact the TRISA admins
at <a href="mailto:[email protected]">[email protected]</a> or on our community
Expand Down
2 changes: 1 addition & 1 deletion pkg/gds/emails/templates/verify_contact.txt
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ Thank you for submitting a TRISA network registration request. To begin the revi

If you cannot click on the link, please copy and paste the link below into your browser address bar:

{{ .VerifyContactURL }}
{{ .VerifyContactURLUnencoded }}

If you're having trouble verifying your contact email, please contact the TRISA admins at [email protected] or on our community Slack channel trisa-workspace.slack.com.

Expand Down

0 comments on commit 7526b28

Please sign in to comment.