From 58397f853a31773f24ad4e62dc1f34df0a975d53 Mon Sep 17 00:00:00 2001 From: Joram Wilander Date: Mon, 27 Mar 2017 09:21:48 -0400 Subject: Implement some MFA endpoints for APIv4 (#5864) --- model/client4.go | 30 ++++++++++++++++++++++++++++++ model/mfa_secret.go | 34 ++++++++++++++++++++++++++++++++++ model/mfa_secret_test.go | 19 +++++++++++++++++++ 3 files changed, 83 insertions(+) create mode 100644 model/mfa_secret.go create mode 100644 model/mfa_secret_test.go (limited to 'model') diff --git a/model/client4.go b/model/client4.go index 6306039ff..72d8951b9 100644 --- a/model/client4.go +++ b/model/client4.go @@ -545,6 +545,36 @@ func (c *Client4) UpdateUserMfa(userId, code string, activate bool) (bool, *Resp } } +// CheckUserMfa checks whether a user has MFA active on their account or not based on the +// provided login id. +func (c *Client4) CheckUserMfa(loginId string) (bool, *Response) { + requestBody := make(map[string]interface{}) + requestBody["login_id"] = loginId + + if r, err := c.DoApiPost(c.GetUsersRoute()+"/mfa", StringInterfaceToJson(requestBody)); err != nil { + return false, &Response{StatusCode: r.StatusCode, Error: err} + } else { + defer closeBody(r) + data := StringInterfaceFromJson(r.Body) + if mfaRequired, ok := data["mfa_required"].(bool); !ok { + return false, BuildResponse(r) + } else { + return mfaRequired, BuildResponse(r) + } + } +} + +// GenerateMfaSecret will generate a new MFA secret for a user and return it as a string and +// as a base64 encoded image QR code. +func (c *Client4) GenerateMfaSecret(userId string) (*MfaSecret, *Response) { + if r, err := c.DoApiPost(c.GetUserRoute(userId)+"/mfa/generate", ""); err != nil { + return nil, &Response{StatusCode: r.StatusCode, Error: err} + } else { + defer closeBody(r) + return MfaSecretFromJson(r.Body), BuildResponse(r) + } +} + // UpdateUserPassword updates a user's password. Must be logged in as the user or be a system administrator. func (c *Client4) UpdateUserPassword(userId, currentPassword, newPassword string) (bool, *Response) { requestBody := map[string]string{"current_password": currentPassword, "new_password": newPassword} diff --git a/model/mfa_secret.go b/model/mfa_secret.go new file mode 100644 index 000000000..717681b3d --- /dev/null +++ b/model/mfa_secret.go @@ -0,0 +1,34 @@ +// Copyright (c) 2017 Mattermost, Inc. All Rights Reserved. +// See License.txt for license information. + +package model + +import ( + "encoding/json" + "io" +) + +type MfaSecret struct { + Secret string `json:"secret"` + QRCode string `json:"qr_code"` +} + +func (me *MfaSecret) ToJson() string { + b, err := json.Marshal(me) + if err != nil { + return "" + } else { + return string(b) + } +} + +func MfaSecretFromJson(data io.Reader) *MfaSecret { + decoder := json.NewDecoder(data) + var me MfaSecret + err := decoder.Decode(&me) + if err == nil { + return &me + } else { + return nil + } +} diff --git a/model/mfa_secret_test.go b/model/mfa_secret_test.go new file mode 100644 index 000000000..c062e7311 --- /dev/null +++ b/model/mfa_secret_test.go @@ -0,0 +1,19 @@ +// Copyright (c) 2017 Mattermost, Inc. All Rights Reserved. +// See License.txt for license information. + +package model + +import ( + "strings" + "testing" +) + +func TestMfaSecretJson(t *testing.T) { + secret := MfaSecret{Secret: NewId(), QRCode: NewId()} + json := secret.ToJson() + result := MfaSecretFromJson(strings.NewReader(json)) + + if secret.Secret != result.Secret { + t.Fatal("Secrets do not match") + } +} -- cgit v1.2.3-1-g7c22