From 379edf73a37ccf0a382bed3eed9ff083f3ed0af9 Mon Sep 17 00:00:00 2001 From: Jordan Wright Date: Mon, 18 Jan 2016 21:13:32 -0600 Subject: [PATCH] Adding first round of database migrations using goose --- config.json | 3 +- config/config.go | 9 +++--- controllers/api_test.go | 3 +- db/migrations/20160118194630_init.sql | 28 ++++++++++++++++++ models/models.go | 41 ++++++++++++++++++--------- models/models_test.go | 1 + 6 files changed, 66 insertions(+), 19 deletions(-) create mode 100644 db/migrations/20160118194630_init.sql diff --git a/config.json b/config.json index 7b7213c9..8aae33de 100644 --- a/config.json +++ b/config.json @@ -16,5 +16,6 @@ "user" : "username", "pass" : "password" }, - "db_path" : "gophish.db" + "db_path" : "gophish.db", + "migrations_path" : "db/migrations/" } diff --git a/config/config.go b/config/config.go index 6f1f5e01..669de289 100644 --- a/config/config.go +++ b/config/config.go @@ -31,10 +31,11 @@ type PhishServer struct { // Config represents the configuration information. type Config struct { - AdminConf AdminServer `json:"admin_server"` - PhishConf PhishServer `json:"phish_server"` - SMTPConf SMTPServer `json:"smtp"` - DBPath string `json:"db_path"` + AdminConf AdminServer `json:"admin_server"` + PhishConf PhishServer `json:"phish_server"` + SMTPConf SMTPServer `json:"smtp"` + DBPath string `json:"db_path"` + MigrationsPath string `json:"migrations_path"` } var Conf Config diff --git a/controllers/api_test.go b/controllers/api_test.go index 4afccd11..893d1f7c 100644 --- a/controllers/api_test.go +++ b/controllers/api_test.go @@ -9,9 +9,9 @@ import ( "os" "testing" - "github.com/gorilla/handlers" "github.com/gophish/gophish/config" "github.com/gophish/gophish/models" + "github.com/gorilla/handlers" "github.com/stretchr/testify/suite" ) @@ -26,6 +26,7 @@ var as *httptest.Server = httptest.NewUnstartedServer(handlers.CombinedLoggingHa func (s *ControllersSuite) SetupSuite() { config.Conf.DBPath = ":memory:" + config.Conf.MigrationsPath = "../db/migrations/" err := models.Setup() if err != nil { s.T().Fatalf("Failed creating database: %v", err) diff --git a/db/migrations/20160118194630_init.sql b/db/migrations/20160118194630_init.sql new file mode 100644 index 00000000..390c8d52 --- /dev/null +++ b/db/migrations/20160118194630_init.sql @@ -0,0 +1,28 @@ + +-- +goose Up +-- SQL in section 'Up' is executed when this migration is applied +CREATE TABLE IF NOT EXISTS "users" ("id" integer primary key autoincrement,"username" varchar(255) NOT NULL UNIQUE,"hash" varchar(255),"api_key" varchar(255) NOT NULL UNIQUE ); +CREATE TABLE IF NOT EXISTS "templates" ("id" integer primary key autoincrement,"user_id" bigint,"name" varchar(255),"subject" varchar(255),"text" varchar(255),"html" varchar(255),"modified_date" datetime ); +CREATE TABLE IF NOT EXISTS "targets" ("id" integer primary key autoincrement,"first_name" varchar(255),"last_name" varchar(255),"email" varchar(255),"position" varchar(255) ); +CREATE TABLE IF NOT EXISTS "smtp" ("smtp_id" integer primary key autoincrement,"campaign_id" bigint,"host" varchar(255),"username" varchar(255),"from_address" varchar(255) ); +CREATE TABLE IF NOT EXISTS "results" ("id" integer primary key autoincrement,"campaign_id" bigint,"user_id" bigint,"r_id" varchar(255),"email" varchar(255),"first_name" varchar(255),"last_name" varchar(255),"status" varchar(255) NOT NULL ,"ip" varchar(255),"latitude" real,"longitude" real ); +CREATE TABLE IF NOT EXISTS "pages" ("id" integer primary key autoincrement,"user_id" bigint,"name" varchar(255),"html" varchar(255),"modified_date" datetime ); +CREATE TABLE IF NOT EXISTS "groups" ("id" integer primary key autoincrement,"user_id" bigint,"name" varchar(255),"modified_date" datetime ); +CREATE TABLE IF NOT EXISTS "group_targets" ("group_id" bigint,"target_id" bigint ); +CREATE TABLE IF NOT EXISTS "events" ("id" integer primary key autoincrement,"campaign_id" bigint,"email" varchar(255),"time" datetime,"message" varchar(255) ); +CREATE TABLE IF NOT EXISTS "campaigns" ("id" integer primary key autoincrement,"user_id" bigint,"name" varchar(255) NOT NULL ,"created_date" datetime,"completed_date" datetime,"template_id" bigint,"page_id" bigint,"status" varchar(255),"url" varchar(255) ); +CREATE TABLE IF NOT EXISTS "attachments" ("id" integer primary key autoincrement,"template_id" bigint,"content" varchar(255),"type" varchar(255),"name" varchar(255) ); + +-- +goose Down +-- SQL section 'Down' is executed when this migration is rolled back +DROP TABLE "attachments"; +DROP TABLE "campaigns"; +DROP TABLE "events"; +DROP TABLE "group_targets"; +DROP TABLE "groups"; +DROP TABLE "pages"; +DROP TABLE "results"; +DROP TABLE "smtp"; +DROP TABLE "targets"; +DROP TABLE "templates"; +DROP TABLE "users"; diff --git a/models/models.go b/models/models.go index 530ce55d..326d326b 100644 --- a/models/models.go +++ b/models/models.go @@ -8,6 +8,8 @@ import ( "log" "os" + "bitbucket.org/liamstask/goose/lib/goose" + "github.com/gophish/gophish/config" "github.com/jinzhu/gorm" _ "github.com/mattn/go-sqlite3" // Blank import needed to import sqlite3 @@ -62,6 +64,24 @@ func Setup() error { if _, err = os.Stat(config.Conf.DBPath); err != nil || config.Conf.DBPath == ":memory:" { create_db = true } + // Setup the goose configuration + migrateConf := &goose.DBConf{ + MigrationsDir: config.Conf.MigrationsPath, + Env: "production", + Driver: goose.DBDriver{ + Name: "sqlite3", + OpenStr: config.Conf.DBPath, + Import: "github.com/mattn/go-sqlite3", + Dialect: &goose.Sqlite3Dialect{}, + }, + } + // Get the latest possible migration + latest, err := goose.GetMostRecentDBVersion(migrateConf.MigrationsDir) + if err != nil { + Logger.Println(err) + return err + } + // Open our database connection db, err = gorm.Open("sqlite3", config.Conf.DBPath) db.LogMode(false) db.SetLogger(Logger) @@ -69,20 +89,14 @@ func Setup() error { Logger.Println(err) return err } - //If the file already exists, delete it and recreate it + // Migrate up to the latest version + err = goose.RunMigrationsOnDb(migrateConf, migrateConf.MigrationsDir, latest, db.DB()) + if err != nil { + Logger.Println(err) + return err + } + //If the database didn't exist, we need to create the admin user if create_db { - Logger.Printf("Database not found... creating db at %s\n", config.Conf.DBPath) - db.CreateTable(User{}) - db.CreateTable(Target{}) - db.CreateTable(Result{}) - db.CreateTable(Group{}) - db.CreateTable(GroupTarget{}) - db.CreateTable(Template{}) - db.CreateTable(Attachment{}) - db.CreateTable(Page{}) - db.CreateTable(SMTP{}) - db.CreateTable(Event{}) - db.CreateTable(Campaign{}) //Create the default user initUser := User{ Username: "admin", @@ -92,6 +106,7 @@ func Setup() error { err = db.Save(&initUser).Error if err != nil { Logger.Println(err) + return err } } return nil diff --git a/models/models_test.go b/models/models_test.go index 99fd3a00..ec84a5b6 100644 --- a/models/models_test.go +++ b/models/models_test.go @@ -16,6 +16,7 @@ var _ = check.Suite(&ModelsSuite{}) func (s *ModelsSuite) SetUpSuite(c *check.C) { config.Conf.DBPath = ":memory:" + config.Conf.MigrationsPath = "../db/migrations/" err := Setup() if err != nil { c.Fatalf("Failed creating database: %v", err)