DodoApp: Implement internal auth

Follow up change will make internal auth optional, and let user
configure dodo-app to use environment wise auth service.

Change-Id: Ie308b30becd4390f3d9a07caf6f894b8bd4ebf3a
diff --git a/core/installer/welcome/store.go b/core/installer/welcome/store.go
index 0ae5f4e..857045c 100644
--- a/core/installer/welcome/store.go
+++ b/core/installer/welcome/store.go
@@ -2,18 +2,33 @@
 
 import (
 	"database/sql"
+	"errors"
+
+	"github.com/ncruces/go-sqlite3"
 
 	"github.com/giolekva/pcloud/core/installer/soft"
 )
 
+const (
+	errorUniqueConstraintViolation = 2067
+)
+
+var (
+	ErrorAlreadyExists = errors.New("already exists")
+)
+
 type Commit struct {
 	Hash    string
 	Message string
 }
 
 type Store interface {
+	CreateUser(username string, password []byte) error
+	GetUserPassword(username string) ([]byte, error)
 	GetApps() ([]string, error)
-	CreateApp(name string) error
+	GetUserApps(username string) ([]string, error)
+	CreateApp(name, username string) error
+	GetAppOwner(name string) (string, error)
 	CreateCommit(name, hash, message string) error
 	GetCommitHistory(name string) ([]Commit, error)
 }
@@ -33,8 +48,13 @@
 
 func (s *storeImpl) init() error {
 	_, err := s.db.Exec(`
+		CREATE TABLE IF NOT EXISTS users (
+			username TEXT PRIMARY KEY,
+            password BLOB
+		);
 		CREATE TABLE IF NOT EXISTS apps (
-			name TEXT PRIMARY KEY
+			name TEXT PRIMARY KEY,
+            username TEXT
 		);
 		CREATE TABLE IF NOT EXISTS commits (
 			app_name TEXT,
@@ -46,12 +66,50 @@
 
 }
 
-func (s *storeImpl) CreateApp(name string) error {
-	query := `INSERT INTO apps (name) VALUES (?)`
-	_, err := s.db.Exec(query, name)
+func (s *storeImpl) CreateUser(username string, password []byte) error {
+	query := `INSERT INTO users (username, password) VALUES (?, ?)`
+	_, err := s.db.Exec(query, username, password)
+	if err != nil {
+		sqliteErr, ok := err.(*sqlite3.Error)
+		if ok && sqliteErr.ExtendedCode() == errorUniqueConstraintViolation {
+			return ErrorAlreadyExists
+		}
+	}
 	return err
 }
 
+func (s *storeImpl) GetUserPassword(username string) ([]byte, error) {
+	query := `SELECT password FROM users WHERE username = ?`
+	row := s.db.QueryRow(query, username)
+	if err := row.Err(); err != nil {
+		return nil, err
+	}
+	ret := []byte{}
+	if err := row.Scan(&ret); err != nil {
+		return nil, err
+	}
+	return ret, nil
+}
+
+func (s *storeImpl) CreateApp(name, username string) error {
+	query := `INSERT INTO apps (name, username) VALUES (?, ?)`
+	_, err := s.db.Exec(query, name, username)
+	return err
+}
+
+func (s *storeImpl) GetAppOwner(name string) (string, error) {
+	query := `SELECT username FROM apps WHERE name = ?`
+	row := s.db.QueryRow(query, name)
+	if err := row.Err(); err != nil {
+		return "", err
+	}
+	var ret string
+	if err := row.Scan(&ret); err != nil {
+		return "", err
+	}
+	return ret, nil
+}
+
 func (s *storeImpl) GetApps() ([]string, error) {
 	query := `SELECT name FROM apps`
 	rows, err := s.db.Query(query)
@@ -74,6 +132,28 @@
 	return ret, nil
 }
 
+func (s *storeImpl) GetUserApps(username string) ([]string, error) {
+	query := `SELECT name FROM apps WHERE username = ?`
+	rows, err := s.db.Query(query, username)
+	if err != nil {
+		return nil, err
+	}
+	defer rows.Close()
+	ret := []string{}
+	for rows.Next() {
+		if err := rows.Err(); err != nil {
+			return nil, err
+		}
+		var name string
+		if err := rows.Scan(&name); err != nil {
+			return nil, err
+		}
+		ret = append(ret, name)
+
+	}
+	return ret, nil
+}
+
 func (s *storeImpl) CreateCommit(name, hash, message string) error {
 	query := `INSERT INTO commits (app_name, hash, message) VALUES (?, ?, ?)`
 	_, err := s.db.Exec(query, name, hash, message)