storage.go 2.4 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13 14
// Copyright 2017 Vector Creations Ltd
//
// 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.

K
Kegsay 已提交
15
package accounts
16 17 18

import (
	"database/sql"
19
	"github.com/matrix-org/dendrite/clientapi/auth/authtypes"
20 21
	"github.com/matrix-org/gomatrixserverlib"
	"golang.org/x/crypto/bcrypt"
22 23
	// Import the postgres database driver.
	_ "github.com/lib/pq"
24 25
)

K
Kegsay 已提交
26 27
// Database represents an account database
type Database struct {
28 29 30 31
	db       *sql.DB
	accounts accountsStatements
}

K
Kegsay 已提交
32 33
// NewDatabase creates a new accounts database
func NewDatabase(dataSourceName string, serverName gomatrixserverlib.ServerName) (*Database, error) {
34 35 36 37 38 39 40 41 42
	var db *sql.DB
	var err error
	if db, err = sql.Open("postgres", dataSourceName); err != nil {
		return nil, err
	}
	a := accountsStatements{}
	if err = a.prepare(db, serverName); err != nil {
		return nil, err
	}
K
Kegsay 已提交
43
	return &Database{db, a}, nil
44 45 46 47
}

// GetAccountByPassword returns the account associated with the given localpart and password.
// Returns sql.ErrNoRows if no account exists which matches the given credentials.
48
func (d *Database) GetAccountByPassword(localpart, plaintextPassword string) (*authtypes.Account, error) {
49 50 51 52 53 54 55 56 57 58 59 60
	hash, err := d.accounts.selectPasswordHash(localpart)
	if err != nil {
		return nil, err
	}
	if err := bcrypt.CompareHashAndPassword([]byte(hash), []byte(plaintextPassword)); err != nil {
		return nil, err
	}
	return d.accounts.selectAccountByLocalpart(localpart)
}

// CreateAccount makes a new account with the given login name and password. If no password is supplied,
// the account will be a passwordless account.
61
func (d *Database) CreateAccount(localpart, plaintextPassword string) (*authtypes.Account, error) {
62 63 64 65 66 67 68 69 70 71 72
	hash, err := hashPassword(plaintextPassword)
	if err != nil {
		return nil, err
	}
	return d.accounts.insertAccount(localpart, hash)
}

func hashPassword(plaintext string) (hash string, err error) {
	hashBytes, err := bcrypt.GenerateFromPassword([]byte(plaintext), bcrypt.DefaultCost)
	return string(hashBytes), err
}