Migration
This commit is contained in:
@@ -316,7 +316,7 @@ const (
|
|||||||
|
|
||||||
// Schema management queries
|
// Schema management queries
|
||||||
const (
|
const (
|
||||||
currentSchemaVersion = 5
|
currentSchemaVersion = 6
|
||||||
insertSchemaVersion = `INSERT INTO schemaVersion VALUES (1, ?)`
|
insertSchemaVersion = `INSERT INTO schemaVersion VALUES (1, ?)`
|
||||||
updateSchemaVersion = `UPDATE schemaVersion SET version = ? WHERE id = 1`
|
updateSchemaVersion = `UPDATE schemaVersion SET version = ? WHERE id = 1`
|
||||||
selectSchemaVersionQuery = `SELECT version FROM schemaVersion WHERE id = 1`
|
selectSchemaVersionQuery = `SELECT version FROM schemaVersion WHERE id = 1`
|
||||||
@@ -434,11 +434,78 @@ const (
|
|||||||
|
|
||||||
// 5 -> 6
|
// 5 -> 6
|
||||||
migrate5To6UpdateQueries = `
|
migrate5To6UpdateQueries = `
|
||||||
ALTER TABLE user ADD COLUMN provisioned INT NOT NULL DEFAULT (0);
|
PRAGMA foreign_keys=off;
|
||||||
ALTER TABLE user ALTER COLUMN provisioned DROP DEFAULT;
|
|
||||||
|
|
||||||
ALTER TABLE user_access ADD COLUMN provisioned INT NOT NULL DEFAULT (0);
|
-- Alter user table: Add provisioned column
|
||||||
ALTER TABLE user_access ALTER COLUMN provisioned DROP DEFAULT;
|
ALTER TABLE user RENAME TO user_old;
|
||||||
|
CREATE TABLE IF NOT EXISTS user (
|
||||||
|
id TEXT PRIMARY KEY,
|
||||||
|
tier_id TEXT,
|
||||||
|
user TEXT NOT NULL,
|
||||||
|
pass TEXT NOT NULL,
|
||||||
|
role TEXT CHECK (role IN ('anonymous', 'admin', 'user')) NOT NULL,
|
||||||
|
prefs JSON NOT NULL DEFAULT '{}',
|
||||||
|
sync_topic TEXT NOT NULL,
|
||||||
|
provisioned INT NOT NULL,
|
||||||
|
stats_messages INT NOT NULL DEFAULT (0),
|
||||||
|
stats_emails INT NOT NULL DEFAULT (0),
|
||||||
|
stats_calls INT NOT NULL DEFAULT (0),
|
||||||
|
stripe_customer_id TEXT,
|
||||||
|
stripe_subscription_id TEXT,
|
||||||
|
stripe_subscription_status TEXT,
|
||||||
|
stripe_subscription_interval TEXT,
|
||||||
|
stripe_subscription_paid_until INT,
|
||||||
|
stripe_subscription_cancel_at INT,
|
||||||
|
created INT NOT NULL,
|
||||||
|
deleted INT,
|
||||||
|
FOREIGN KEY (tier_id) REFERENCES tier (id)
|
||||||
|
);
|
||||||
|
INSERT INTO user
|
||||||
|
SELECT
|
||||||
|
id,
|
||||||
|
tier_id,
|
||||||
|
user,
|
||||||
|
pass,
|
||||||
|
role,
|
||||||
|
prefs,
|
||||||
|
sync_topic,
|
||||||
|
0,
|
||||||
|
stats_messages,
|
||||||
|
stats_emails,
|
||||||
|
stats_calls,
|
||||||
|
stripe_customer_id,
|
||||||
|
stripe_subscription_id,
|
||||||
|
stripe_subscription_status,
|
||||||
|
stripe_subscription_interval,
|
||||||
|
stripe_subscription_paid_until,
|
||||||
|
stripe_subscription_cancel_at,
|
||||||
|
created, deleted
|
||||||
|
FROM user_old;
|
||||||
|
DROP TABLE user_old;
|
||||||
|
|
||||||
|
-- Alter user_access table: Add provisioned column
|
||||||
|
ALTER TABLE user_access RENAME TO user_access_old;
|
||||||
|
CREATE TABLE user_access (
|
||||||
|
user_id TEXT NOT NULL,
|
||||||
|
topic TEXT NOT NULL,
|
||||||
|
read INT NOT NULL,
|
||||||
|
write INT NOT NULL,
|
||||||
|
owner_user_id INT,
|
||||||
|
provisioned INTEGER NOT NULL,
|
||||||
|
PRIMARY KEY (user_id, topic),
|
||||||
|
FOREIGN KEY (user_id) REFERENCES user (id) ON DELETE CASCADE,
|
||||||
|
FOREIGN KEY (owner_user_id) REFERENCES user (id) ON DELETE CASCADE
|
||||||
|
);
|
||||||
|
INSERT INTO user_access SELECT *, 0 FROM user_access_old;
|
||||||
|
DROP TABLE user_access_old;
|
||||||
|
|
||||||
|
-- Recreate indices
|
||||||
|
CREATE UNIQUE INDEX idx_user ON user (user);
|
||||||
|
CREATE UNIQUE INDEX idx_user_stripe_customer_id ON user (stripe_customer_id);
|
||||||
|
CREATE UNIQUE INDEX idx_user_stripe_subscription_id ON user (stripe_subscription_id);
|
||||||
|
|
||||||
|
-- Re-enable foreign keys
|
||||||
|
PRAGMA foreign_keys=on;
|
||||||
`
|
`
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -1422,10 +1489,10 @@ func (a *Manager) AddReservation(username string, topic string, everyone Permiss
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
defer tx.Rollback()
|
defer tx.Rollback()
|
||||||
if _, err := tx.Exec(upsertUserAccessQuery, username, escapeUnderscore(topic), true, true, username, username); err != nil {
|
if _, err := tx.Exec(upsertUserAccessQuery, username, escapeUnderscore(topic), true, true, username, username, false); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
if _, err := tx.Exec(upsertUserAccessQuery, Everyone, escapeUnderscore(topic), everyone.IsRead(), everyone.IsWrite(), username, username); err != nil {
|
if _, err := tx.Exec(upsertUserAccessQuery, Everyone, escapeUnderscore(topic), everyone.IsRead(), everyone.IsWrite(), username, username, false); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
return tx.Commit()
|
return tx.Commit()
|
||||||
|
|||||||
@@ -52,10 +52,10 @@ func TestManager_FullScenario_Default_DenyAll(t *testing.T) {
|
|||||||
benGrants, err := a.Grants("ben")
|
benGrants, err := a.Grants("ben")
|
||||||
require.Nil(t, err)
|
require.Nil(t, err)
|
||||||
require.Equal(t, []Grant{
|
require.Equal(t, []Grant{
|
||||||
{"everyonewrite", PermissionDenyAll},
|
{"everyonewrite", PermissionDenyAll, false},
|
||||||
{"mytopic", PermissionReadWrite},
|
{"mytopic", PermissionReadWrite, false},
|
||||||
{"writeme", PermissionWrite},
|
{"writeme", PermissionWrite, false},
|
||||||
{"readme", PermissionRead},
|
{"readme", PermissionRead, false},
|
||||||
}, benGrants)
|
}, benGrants)
|
||||||
|
|
||||||
john, err := a.Authenticate("john", "john")
|
john, err := a.Authenticate("john", "john")
|
||||||
@@ -67,10 +67,10 @@ func TestManager_FullScenario_Default_DenyAll(t *testing.T) {
|
|||||||
johnGrants, err := a.Grants("john")
|
johnGrants, err := a.Grants("john")
|
||||||
require.Nil(t, err)
|
require.Nil(t, err)
|
||||||
require.Equal(t, []Grant{
|
require.Equal(t, []Grant{
|
||||||
{"mytopic_deny*", PermissionDenyAll},
|
{"mytopic_deny*", PermissionDenyAll, false},
|
||||||
{"mytopic_ro*", PermissionRead},
|
{"mytopic_ro*", PermissionRead, false},
|
||||||
{"mytopic*", PermissionReadWrite},
|
{"mytopic*", PermissionReadWrite, false},
|
||||||
{"*", PermissionRead},
|
{"*", PermissionRead, false},
|
||||||
}, johnGrants)
|
}, johnGrants)
|
||||||
|
|
||||||
notben, err := a.Authenticate("ben", "this is wrong")
|
notben, err := a.Authenticate("ben", "this is wrong")
|
||||||
@@ -277,10 +277,10 @@ func TestManager_UserManagement(t *testing.T) {
|
|||||||
benGrants, err := a.Grants("ben")
|
benGrants, err := a.Grants("ben")
|
||||||
require.Nil(t, err)
|
require.Nil(t, err)
|
||||||
require.Equal(t, []Grant{
|
require.Equal(t, []Grant{
|
||||||
{"everyonewrite", PermissionDenyAll},
|
{"everyonewrite", PermissionDenyAll, false},
|
||||||
{"mytopic", PermissionReadWrite},
|
{"mytopic", PermissionReadWrite, false},
|
||||||
{"writeme", PermissionWrite},
|
{"writeme", PermissionWrite, false},
|
||||||
{"readme", PermissionRead},
|
{"readme", PermissionRead, false},
|
||||||
}, benGrants)
|
}, benGrants)
|
||||||
|
|
||||||
everyone, err := a.User(Everyone)
|
everyone, err := a.User(Everyone)
|
||||||
@@ -292,8 +292,8 @@ func TestManager_UserManagement(t *testing.T) {
|
|||||||
everyoneGrants, err := a.Grants(Everyone)
|
everyoneGrants, err := a.Grants(Everyone)
|
||||||
require.Nil(t, err)
|
require.Nil(t, err)
|
||||||
require.Equal(t, []Grant{
|
require.Equal(t, []Grant{
|
||||||
{"everyonewrite", PermissionReadWrite},
|
{"everyonewrite", PermissionReadWrite, false},
|
||||||
{"announcements", PermissionRead},
|
{"announcements", PermissionRead, false},
|
||||||
}, everyoneGrants)
|
}, everyoneGrants)
|
||||||
|
|
||||||
// Ben: Before revoking
|
// Ben: Before revoking
|
||||||
@@ -1099,19 +1099,98 @@ func TestManager_Topic_Wildcard_With_Underscore(t *testing.T) {
|
|||||||
func TestManager_WithProvisionedUsers(t *testing.T) {
|
func TestManager_WithProvisionedUsers(t *testing.T) {
|
||||||
f := filepath.Join(t.TempDir(), "user.db")
|
f := filepath.Join(t.TempDir(), "user.db")
|
||||||
conf := &Config{
|
conf := &Config{
|
||||||
Filename: f,
|
Filename: f,
|
||||||
DefaultAccess: PermissionReadWrite,
|
DefaultAccess: PermissionReadWrite,
|
||||||
ProvisionedUsers: []*User{
|
ProvisionEnabled: true,
|
||||||
{Name: "phil", Hash: "$2a$10$YLiO8U21sX1uhZamTLJXHuxgVC0Z/GKISibrKCLohPgtG7yIxSk4C", Role: RoleAdmin},
|
ProvisionUsers: []*User{
|
||||||
|
{Name: "philuser", Hash: "$2a$10$YLiO8U21sX1uhZamTLJXHuxgVC0Z/GKISibrKCLohPgtG7yIxSk4C", Role: RoleUser},
|
||||||
|
{Name: "philadmin", Hash: "$2a$10$YLiO8U21sX1uhZamTLJXHuxgVC0Z/GKISibrKCLohPgtG7yIxSk4C", Role: RoleAdmin},
|
||||||
|
},
|
||||||
|
ProvisionAccess: map[string][]*Grant{
|
||||||
|
"philuser": {
|
||||||
|
{TopicPattern: "stats", Permission: PermissionReadWrite},
|
||||||
|
{TopicPattern: "secret", Permission: PermissionRead},
|
||||||
|
},
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
a, err := NewManager(conf)
|
a, err := NewManager(conf)
|
||||||
require.Nil(t, err)
|
require.Nil(t, err)
|
||||||
|
|
||||||
|
// Manually add user
|
||||||
|
require.Nil(t, a.AddUser("philmanual", "manual", RoleUser, false))
|
||||||
|
|
||||||
|
// Check that the provisioned users are there
|
||||||
users, err := a.Users()
|
users, err := a.Users()
|
||||||
require.Nil(t, err)
|
require.Nil(t, err)
|
||||||
for _, u := range users {
|
require.Len(t, users, 4)
|
||||||
fmt.Println(u.ID, u.Name, u.Role)
|
|
||||||
|
require.Equal(t, "philadmin", users[0].Name)
|
||||||
|
require.Equal(t, RoleAdmin, users[0].Role)
|
||||||
|
|
||||||
|
require.Equal(t, "philmanual", users[1].Name)
|
||||||
|
require.Equal(t, RoleUser, users[1].Role)
|
||||||
|
|
||||||
|
grants, err := a.Grants("philuser")
|
||||||
|
require.Nil(t, err)
|
||||||
|
require.Equal(t, "philuser", users[2].Name)
|
||||||
|
require.Equal(t, RoleUser, users[2].Role)
|
||||||
|
require.Equal(t, 2, len(grants))
|
||||||
|
require.Equal(t, "secret", grants[0].TopicPattern)
|
||||||
|
require.Equal(t, PermissionRead, grants[0].Permission)
|
||||||
|
require.Equal(t, "stats", grants[1].TopicPattern)
|
||||||
|
require.Equal(t, PermissionReadWrite, grants[1].Permission)
|
||||||
|
|
||||||
|
require.Equal(t, "*", users[3].Name)
|
||||||
|
|
||||||
|
// Re-open the DB (second app start)
|
||||||
|
require.Nil(t, a.db.Close())
|
||||||
|
conf.ProvisionUsers = []*User{
|
||||||
|
{Name: "philuser", Hash: "$2a$10$AAAU21sX1uhZamTLJXHuxgVC0Z/GKISibrKCLohPgtG7yIxSk4C", Role: RoleUser},
|
||||||
}
|
}
|
||||||
|
conf.ProvisionAccess = map[string][]*Grant{
|
||||||
|
"philuser": {
|
||||||
|
{TopicPattern: "stats12", Permission: PermissionReadWrite},
|
||||||
|
{TopicPattern: "secret12", Permission: PermissionRead},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
a, err = NewManager(conf)
|
||||||
|
require.Nil(t, err)
|
||||||
|
|
||||||
|
// Check that the provisioned users are there
|
||||||
|
users, err = a.Users()
|
||||||
|
require.Nil(t, err)
|
||||||
|
require.Len(t, users, 3)
|
||||||
|
|
||||||
|
require.Equal(t, "philmanual", users[0].Name)
|
||||||
|
require.Equal(t, RoleUser, users[0].Role)
|
||||||
|
|
||||||
|
grants, err = a.Grants("philuser")
|
||||||
|
require.Nil(t, err)
|
||||||
|
require.Equal(t, "philuser", users[1].Name)
|
||||||
|
require.Equal(t, RoleUser, users[1].Role)
|
||||||
|
require.Equal(t, 2, len(grants))
|
||||||
|
require.Equal(t, "secret12", grants[0].TopicPattern)
|
||||||
|
require.Equal(t, PermissionRead, grants[0].Permission)
|
||||||
|
require.Equal(t, "stats12", grants[1].TopicPattern)
|
||||||
|
require.Equal(t, PermissionReadWrite, grants[1].Permission)
|
||||||
|
|
||||||
|
require.Equal(t, "*", users[2].Name)
|
||||||
|
|
||||||
|
// Re-open the DB again (third app start)
|
||||||
|
require.Nil(t, a.db.Close())
|
||||||
|
conf.ProvisionUsers = []*User{}
|
||||||
|
conf.ProvisionAccess = map[string][]*Grant{}
|
||||||
|
a, err = NewManager(conf)
|
||||||
|
require.Nil(t, err)
|
||||||
|
|
||||||
|
// Check that the provisioned users are there
|
||||||
|
users, err = a.Users()
|
||||||
|
require.Nil(t, err)
|
||||||
|
require.Len(t, users, 2)
|
||||||
|
|
||||||
|
require.Equal(t, "philmanual", users[0].Name)
|
||||||
|
require.Equal(t, RoleUser, users[0].Role)
|
||||||
|
require.Equal(t, "*", users[1].Name)
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestToFromSQLWildcard(t *testing.T) {
|
func TestToFromSQLWildcard(t *testing.T) {
|
||||||
|
|||||||
Reference in New Issue
Block a user