Skip to content

Commit

Permalink
Clean up linking
Browse files Browse the repository at this point in the history
- Environment and public key were hardcoded
- Static link template wasn't serving anymore, moved to a template
- Nicer messages in cli and browser
  • Loading branch information
landakram committed Jun 16, 2020
1 parent 5e9a59b commit 7d08063
Show file tree
Hide file tree
Showing 3 changed files with 183 additions and 78 deletions.
2 changes: 1 addition & 1 deletion main.go
Original file line number Diff line number Diff line change
Expand Up @@ -76,7 +76,7 @@ func main() {
log.Fatal(err)
}

linker := plaid_cli.NewLinker(data, client)
linker := plaid_cli.NewLinker(data, client, opts)

linkCommand := &cobra.Command{
Use: "link [ITEM-ID-OR-ALIAS]",
Expand Down
200 changes: 182 additions & 18 deletions pkg/plaid_cli/linker.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,10 +12,11 @@ import (
)

type Linker struct {
Results chan string
Errors chan error
Client *plaid.Client
Data *Data
Results chan string
Errors chan error
Client *plaid.Client
ClientOpts plaid.ClientOptions
Data *Data
}

type TokenPair struct {
Expand All @@ -38,7 +39,8 @@ func (l *Linker) Link(port string) (*TokenPair, error) {
}

func (l *Linker) link(port string, serveLink func(w http.ResponseWriter, r *http.Request)) (*TokenPair, error) {
log.Println(fmt.Sprintf("Starting Plaid Link on port %s", port))
log.Println(fmt.Sprintf("Starting Plaid Link on port %s...", port))

go func() {
http.HandleFunc("/link", serveLink)
err := http.ListenAndServe(fmt.Sprintf(":%s", port), nil)
Expand All @@ -47,7 +49,9 @@ func (l *Linker) link(port string, serveLink func(w http.ResponseWriter, r *http
}
}()

open.Run(fmt.Sprintf("http://localhost:%s/link", port))
url := fmt.Sprintf("http://localhost:%s/link", port)
log.Println(fmt.Sprintf("Your browser should open automatically. If it doesn't, please visit %s to continue linking!", url))
open.Run(url)

select {
case err := <-l.Errors:
Expand All @@ -71,20 +75,39 @@ func (l *Linker) exchange(publicToken string) (plaid.ExchangePublicTokenResponse
return l.Client.ExchangePublicToken(publicToken)
}

func NewLinker(data *Data, client *plaid.Client) *Linker {
func NewLinker(data *Data, client *plaid.Client, clientOpts plaid.ClientOptions) *Linker {
return &Linker{
Results: make(chan string),
Errors: make(chan error),
Client: client,
Data: data,
Results: make(chan string),
Errors: make(chan error),
Client: client,
ClientOpts: clientOpts,
Data: data,
}
}

func handleLink(linker *Linker) func(w http.ResponseWriter, r *http.Request) {
return func(w http.ResponseWriter, r *http.Request) {
switch r.Method {
case http.MethodGet:
http.ServeFile(w, r, "./static/link.html")
t := template.New("link")
t, _ = t.Parse(linkTemplate)

var env string
switch linker.ClientOpts.Environment {
case plaid.Development:
env = "development"
case plaid.Production:
env = "production"
case plaid.Sandbox:
env = "sandbox"
default:
env = "development"
}
d := LinkTmplData{
PublicKey: linker.ClientOpts.PublicKey,
Environment: env,
}
t.Execute(w, d)
case http.MethodPost:
r.ParseForm()
token := r.Form.Get("public_token")
Expand All @@ -101,8 +124,15 @@ func handleLink(linker *Linker) func(w http.ResponseWriter, r *http.Request) {
}
}

type RelinkTemplData struct {
type LinkTmplData struct {
PublicKey string
Environment string
}

type RelinkTmplData struct {
PublicToken string
PublicKey string
Environment string
}

func handleRelink(linker *Linker, publicToken string) func(w http.ResponseWriter, r *http.Request) {
Expand All @@ -111,8 +141,22 @@ func handleRelink(linker *Linker, publicToken string) func(w http.ResponseWriter
case http.MethodGet:
t := template.New("relink")
t, _ = t.Parse(relinkTemplate)
d := RelinkTemplData{

var env string
switch linker.ClientOpts.Environment {
case plaid.Development:
env = "development"
case plaid.Production:
env = "production"
case plaid.Sandbox:
env = "sandbox"
default:
env = "development"
}
d := RelinkTmplData{
PublicToken: publicToken,
PublicKey: linker.ClientOpts.PublicKey,
Environment: env,
}
t.Execute(w, d)
case http.MethodPost:
Expand All @@ -131,7 +175,26 @@ func handleRelink(linker *Linker, publicToken string) func(w http.ResponseWriter
}
}

var relinkTemplate string = `<html>
var linkTemplate string = `<html>
<head>
<style>
.alert-success {
font-size: 1.2em;
font-family: Arial, Helvetica, sans-serif;
background-color: #008000;
color: #fff;
display: flex;
justify-content: center;
align-items: center;
border-radius: 15px;
width: 100%;
height: 100%;
}
.hidden {
visibility: hidden;
}
</style>
</head>
<body>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/2.2.3/jquery.min.js"></script>
<script src="https://cdn.plaid.com/link/v2/stable/link-initialize.js"></script>
Expand All @@ -143,11 +206,11 @@ var relinkTemplate string = `<html>
// codes to initialize Link; European countries will have GDPR
// consent panel
countryCodes: ['US'],
env: 'development',
env: '{{ .Environment }}',
// Replace with your public_key from the Dashboard
key: '880bb11f8bc9f3c1d8feb4a348f371',
key: '{{ .PublicKey }}',
product: ['transactions'],
token: "{{ .PublicToken }}",
// Optional, specify a language to localize Link
language: 'en',
onLoad: function() {
// Optional, called when Link loads
Expand All @@ -169,6 +232,100 @@ var relinkTemplate string = `<html>
// metadata contains information about the institution
// that the user selected and the most recent API request IDs.
// Storing this information can be helpful for support.
document.getElementById("alert").classList.remove("hidden");
},
onEvent: function(eventName, metadata) {
// Optionally capture Link flow events, streamed through
// this callback as your users connect an Item to Plaid.
// For example:
// eventName = "TRANSITION_VIEW"
// metadata = {
// link_session_id: "123-abc",
// mfa_type: "questions",
// timestamp: "2017-09-14T14:42:19.350Z",
// view_name: "MFA",
// }
}
});
handler.open();
})(jQuery);
</script>
<div id="alert" class="alert-success hidden">
<div>
<h2>All done here!</h2>
<p>You can close this window and go back to plaid-cli.</p>
</div>
</div>
</body>
</html> `

var relinkTemplate string = `<html>
<head>
<style>
.alert-success {
font-size: 1.2em;
font-family: Arial, Helvetica, sans-serif;
background-color: #008000;
color: #fff;
display: flex;
justify-content: center;
align-items: center;
border-radius: 15px;
width: 100%;
height: 100%;
}
.hidden {
visibility: hidden;
}
</style>
</head>
<body>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/2.2.3/jquery.min.js"></script>
<script src="https://cdn.plaid.com/link/v2/stable/link-initialize.js"></script>
<script type="text/javascript">
(function($) {
var handler = Plaid.create({
clientName: 'plaid-cli',
// Optional, specify an array of ISO-3166-1 alpha-2 country
// codes to initialize Link; European countries will have GDPR
// consent panel
countryCodes: ['US'],
env: '{{ .Environment }}',
// Replace with your public_key from the Dashboard
key: '{{ .PublicKey }}',
product: ['transactions'],
token: "{{ .PublicToken }}",
language: 'en',
onLoad: function() {
// Optional, called when Link loads
},
onSuccess: function(public_token, metadata) {
console.log("onSuccess");
// Send the public_token to your app server.
// The metadata object contains info about the institution the
// user selected and the account ID or IDs, if the
// Select Account view is enabled.
$.post('/link', {
public_token: public_token,
});
},
onExit: function(err, metadata) {
if (err != null) {
console.log(err);
// Handle manual relink when credential is already valid
if (err.error_code == "item-no-error") {
$.post('/link', {
public_token: "{{ .PublicToken }}",
});
}
}
document.getElementById("alert").classList.remove("hidden");
},
onEvent: function(eventName, metadata) {
// Optionally capture Link flow events, streamed through
Expand All @@ -188,5 +345,12 @@ var relinkTemplate string = `<html>
})(jQuery);
</script>
<div id="alert" class="alert-success hidden">
<div>
<h2>All done here!</h2>
<p>You can close this window and go back to plaid-cli.</p>
</div>
</div>
</body>
</html>`
59 changes: 0 additions & 59 deletions static/link.html

This file was deleted.

0 comments on commit 7d08063

Please sign in to comment.