Skip to content

Commit

Permalink
Merge pull request #6 from Rots/master
Browse files Browse the repository at this point in the history
use standard oauth2 library for authentication
  • Loading branch information
guitmz authored Apr 30, 2018
2 parents b60e816 + 9806506 commit e4152c7
Show file tree
Hide file tree
Showing 2 changed files with 50 additions and 50 deletions.
66 changes: 28 additions & 38 deletions api.go
Original file line number Diff line number Diff line change
@@ -1,12 +1,13 @@
package n26

import (
"context"
"encoding/json"
"fmt"
"golang.org/x/oauth2"
"io/ioutil"
"net/http"
"net/url"
"strings"
)

const apiURL = "https://api.tech26.de"
Expand Down Expand Up @@ -185,40 +186,29 @@ type Statements []struct {
Year int `json:"year"`
}

func (auth Auth) requestToken() string {
token := &Token{}
data := url.Values{}
data.Set("grant_type", "password")
data.Add("username", auth.UserName)
data.Add("password", auth.Password)
type Client http.Client

u, _ := url.ParseRequestURI(apiURL)
u.Path = "/oauth/token"
urlStr := fmt.Sprintf("%v", u)

req, _ := http.NewRequest("POST", urlStr, strings.NewReader(data.Encode()))
req.Header.Add("Authorization", "Basic YW5kcm9pZDpzZWNyZXQ=")
req.Header.Add("Content-Type", "application/x-www-form-urlencoded")

res, err := http.DefaultClient.Do(req)
check(err)
defer res.Body.Close()
body, _ := ioutil.ReadAll(res.Body)
check(json.Unmarshal(body, token))

return token.AccessToken
func NewClient(a Auth) (*Client, error) {
c := oauth2.Config{
ClientID: "android",
ClientSecret: "secret",
Endpoint: oauth2.Endpoint{TokenURL: apiURL + "/oauth/token"},
}
ctx := context.Background()
tok, err := c.PasswordCredentialsToken(ctx, a.UserName, a.Password)
if err != nil {
return nil, err
}
return (*Client)(c.Client(ctx, tok)), nil
}

func (auth Auth) n26Request(endpoint string, params map[string]string) []byte {
func (c *Client) n26Request(endpoint string, params map[string]string) []byte {
u, _ := url.ParseRequestURI(apiURL)
u.Path = endpoint

u.RawQuery = mapToQuery(params).Encode()

req, _ := http.NewRequest("GET", u.String(), nil)
req.Header.Add("Authorization", "bearer "+auth.requestToken())

res, _ := http.DefaultClient.Do(req)
res, _ := (*http.Client)(c).Get(u.String())
defer res.Body.Close()
body, _ := ioutil.ReadAll(res.Body)

Expand All @@ -232,7 +222,7 @@ func mapToQuery(params map[string]string) url.Values {
return values
}

func (auth Auth) GetBalance(retType string) (string, *Balance) {
func (auth *Client) GetBalance(retType string) (string, *Balance) {
body := auth.n26Request("/api/accounts", nil)
balance := &Balance{}
check(json.Unmarshal(body, &balance))
Expand All @@ -243,7 +233,7 @@ func (auth Auth) GetBalance(retType string) (string, *Balance) {
return "", balance
}

func (auth Auth) GetInfo(retType string) (string, *PersonalInfo) {
func (auth *Client) GetInfo(retType string) (string, *PersonalInfo) {
body := auth.n26Request("/api/me", nil)
info := &PersonalInfo{}
check(json.Unmarshal(body, &info))
Expand All @@ -254,7 +244,7 @@ func (auth Auth) GetInfo(retType string) (string, *PersonalInfo) {
return "", info
}

func (auth Auth) GetStatus(retType string) (string, *Statuses) {
func (auth *Client) GetStatus(retType string) (string, *Statuses) {
body := auth.n26Request("/api/me/statuses", nil)
status := &Statuses{}
check(json.Unmarshal(body, &status))
Expand All @@ -265,7 +255,7 @@ func (auth Auth) GetStatus(retType string) (string, *Statuses) {
return "", status
}

func (auth Auth) GetAddresses(retType string) (string, *Addresses) {
func (auth *Client) GetAddresses(retType string) (string, *Addresses) {
body := auth.n26Request("/api/addresses", nil)
addresses := &Addresses{}
check(json.Unmarshal(body, &addresses))
Expand All @@ -276,7 +266,7 @@ func (auth Auth) GetAddresses(retType string) (string, *Addresses) {
return "", addresses
}

func (auth Auth) GetCards(retType string) (string, *Cards) {
func (auth *Client) GetCards(retType string) (string, *Cards) {
body := auth.n26Request("/api/v2/cards", nil)
cards := &Cards{}
check(json.Unmarshal(body, &cards))
Expand All @@ -287,7 +277,7 @@ func (auth Auth) GetCards(retType string) (string, *Cards) {
return "", cards
}

func (auth Auth) GetLimits(retType string) (string, *Limits) {
func (auth *Client) GetLimits(retType string) (string, *Limits) {
body := auth.n26Request("/api/settings/account/limits", nil)
limits := &Limits{}
check(json.Unmarshal(body, &limits))
Expand All @@ -298,7 +288,7 @@ func (auth Auth) GetLimits(retType string) (string, *Limits) {
return "", limits
}

func (auth Auth) GetContacts(retType string) (string, *Contacts) {
func (auth *Client) GetContacts(retType string) (string, *Contacts) {
body := auth.n26Request("/api/smrt/contacts", nil)
contacts := &Contacts{}
check(json.Unmarshal(body, &contacts))
Expand All @@ -309,14 +299,14 @@ func (auth Auth) GetContacts(retType string) (string, *Contacts) {
return "", contacts
}

func (auth Auth) GetLastTransactions() (*Transactions, error) {
func (auth *Client) GetLastTransactions() (*Transactions, error) {
return auth.GetTransactions(TimeStamp{}, TimeStamp{})
}

// Get transactions for the given time window.
// Use the zero values for the time stamps if no restrictions are
// desired (use the defaults on the server)
func (auth Auth) GetTransactions(from, to TimeStamp) (*Transactions, error) {
func (auth *Client) GetTransactions(from, to TimeStamp) (*Transactions, error) {
params := map[string]string{}
//Filter is applied only if both values are set
if !from.IsZero() && !to.IsZero() {
Expand All @@ -331,7 +321,7 @@ func (auth Auth) GetTransactions(from, to TimeStamp) (*Transactions, error) {
return transactions, nil
}

func (auth Auth) GetStatements(retType string) (string, *Statements) {
func (auth *Client) GetStatements(retType string) (string, *Statements) {
body := auth.n26Request("/api/statements", nil)
statements := &Statements{}
check(json.Unmarshal(body, &statements))
Expand All @@ -342,7 +332,7 @@ func (auth Auth) GetStatements(retType string) (string, *Statements) {
return "", statements
}

func (auth Auth) GetStatementPDF(ID string) {
func (auth *Client) GetStatementPDF(ID string) {
body := auth.n26Request(fmt.Sprintf("%s%s", "/api/statements/", ID), nil)
ioutil.WriteFile(
fmt.Sprintf("%s.pdf", ID),
Expand Down
34 changes: 22 additions & 12 deletions cmd/n26/n26.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ func check(e error) {
}
}

func authentication() *n26.Auth {
func authentication() (*n26.Client, error) {
username := os.Getenv("N26_USERNAME")
if username == "" {
fmt.Print("N26 username: ")
Expand All @@ -33,7 +33,7 @@ func authentication() *n26.Auth {
check(err)
password = string(maskedPass)
}
return &n26.Auth{username, password}
return n26.NewClient(n26.Auth{username, password})
}

// Interface for generic data writer that has a header and data table e.g. table writer and csv writer
Expand All @@ -57,7 +57,8 @@ func main() {
Name: "balance",
Usage: "your balance information",
Action: func(c *cli.Context) error {
API := authentication()
API, err := authentication()
check(err)
prettyJSON, balance := API.GetBalance(c.Args().First())
if prettyJSON != "" {
fmt.Println(prettyJSON)
Expand All @@ -74,7 +75,8 @@ func main() {
Name: "info",
Usage: "personal information",
Action: func(c *cli.Context) error {
API := authentication()
API, err := authentication()
check(err)
prettyJSON, info := API.GetInfo(c.Args().First())
if prettyJSON != "" {
fmt.Println(prettyJSON)
Expand All @@ -89,7 +91,8 @@ func main() {
Name: "status",
Usage: "general status of your account",
Action: func(c *cli.Context) error {
API := authentication()
API, err := authentication()
check(err)
prettyJSON, status := API.GetStatus(c.Args().First())
if prettyJSON != "" {
fmt.Println(prettyJSON)
Expand All @@ -108,7 +111,8 @@ func main() {
Name: "addresses",
Usage: "addresses linked to your account",
Action: func(c *cli.Context) error {
API := authentication()
API, err := authentication()
check(err)
prettyJSON, addresses := API.GetAddresses(c.Args().First())
if prettyJSON != "" {
fmt.Println(prettyJSON)
Expand Down Expand Up @@ -142,7 +146,8 @@ func main() {
Name: "cards",
Usage: "list your cards information",
Action: func(c *cli.Context) error {
API := authentication()
API, err := authentication()
check(err)
prettyJSON, cards := API.GetCards(c.Args().First())
if prettyJSON != "" {
fmt.Println(prettyJSON)
Expand All @@ -167,7 +172,8 @@ func main() {
Name: "limits",
Usage: "your account limits",
Action: func(c *cli.Context) error {
API := authentication()
API, err := authentication()
check(err)
prettyJSON, limits := API.GetLimits(c.Args().First())
if prettyJSON != "" {
fmt.Println(prettyJSON)
Expand All @@ -191,7 +197,8 @@ func main() {
Name: "contacts",
Usage: "your saved contacts",
Action: func(c *cli.Context) error {
API := authentication()
API, err := authentication()
check(err)
prettyJSON, contacts := API.GetContacts(c.Args().First())
if prettyJSON != "" {
fmt.Println(prettyJSON)
Expand Down Expand Up @@ -224,7 +231,8 @@ func main() {
},
Action: func(c *cli.Context) (err error) {
const dateFormat = "2006-01-02"
API := authentication()
API, err := authentication()
check(err)
writer, err := getTransactionWriter(c.Args().First())
check(err)
var transactions *n26.Transactions
Expand All @@ -250,7 +258,8 @@ func main() {
Usage: "your statements. Passing the statement ID as argument, downloads the PDF to the current directory",
ArgsUsage: "[statement ID]",
Action: func(c *cli.Context) error {
API := authentication()
API, err := authentication()
check(err)
dateRegex := regexp.MustCompile("statement-[0-9][0-9][0-9][0-9]-(1[0-2]|0[1-9]|\\d)")
argument := c.Args().First()
switch {
Expand Down Expand Up @@ -279,7 +288,8 @@ func main() {
}

sort.Sort(cli.CommandsByName(app.Commands))
app.Run(os.Args)
err := app.Run(os.Args)
check(err)
}

func getTransactionWriter(outType string) (transactionWriter, error) {
Expand Down

0 comments on commit e4152c7

Please sign in to comment.