db.go (view raw)
1package main
2
3import (
4 "crypto/rand"
5 "database/sql"
6 "io"
7 "io/ioutil"
8 "log"
9 "os"
10 "path"
11 "path/filepath"
12 "sort"
13 "time"
14)
15
16var DB *sql.DB
17
18func initializeDB() {
19 var err error
20 DB, err = sql.Open("sqlite3", c.DBFile)
21 if err != nil {
22 log.Fatal(err)
23 }
24 createTablesIfDNE()
25}
26
27func getAnalyticsDB() *sql.DB {
28 db, err := sql.Open("sqlite3", c.AnalyticsDBFile)
29 _, err = db.Exec(`CREATE TABLE IF NOT EXISTS log (
30 id INTEGER PRIMARY KEY NOT NULL,
31 timestamp TEXT NOT NULL,
32 protocol TEXT NOT NULL,
33 request_ip TEXT,
34 request_user TEXT,
35 status INTEGER,
36 destination_host TEXT,
37 path TEXT,
38 method TEXT,
39 referer TEXT
40);`)
41 if err != nil {
42 log.Fatal(err)
43 }
44 return db
45}
46
47type File struct { // also folders
48 Creator string
49 Name string // includes folder
50 UpdatedTime time.Time
51 TimeAgo string
52 IsText bool
53 Children []File
54 Host string
55}
56
57func fileFromPath(fullPath string) File {
58 info, _ := os.Stat(fullPath)
59 creatorFolder := getCreator(fullPath)
60 isText := isTextFile(fullPath)
61 updatedTime := info.ModTime()
62 return File{
63 Name: getLocalPath(fullPath),
64 Creator: path.Base(creatorFolder),
65 UpdatedTime: updatedTime,
66 IsText: isText,
67 TimeAgo: timeago(&updatedTime),
68 Host: c.Host,
69 }
70
71}
72
73type User struct {
74 Username string
75 Email string
76 Active bool
77 Admin bool
78 CreatedAt int // timestamp
79 Reference string
80}
81
82func getActiveUserNames() ([]string, error) {
83 rows, err := DB.Query(`SELECT username from user WHERE active is true order by username`)
84 if err != nil {
85 return nil, err
86 }
87 var users []string
88 for rows.Next() {
89 var user string
90 err = rows.Scan(&user)
91 if err != nil {
92 return nil, err
93 }
94 users = append(users, user)
95 }
96
97 return users, nil
98}
99
100func getUserByName(username string) (*User, error) {
101 var user User
102 row := DB.QueryRow(`SELECT username, email, active, admin, created_at, reference from user WHERE username = ?`, username)
103 err := row.Scan(&user.Username, &user.Email, &user.Active, &user.Admin, &user.CreatedAt, &user.Reference)
104 if err != nil {
105 return nil, err
106 }
107 return &user, nil
108}
109
110func getUsers() ([]User, error) {
111 rows, err := DB.Query(`SELECT username, email, active, admin, created_at, reference from user ORDER BY created_at DESC`)
112 if err != nil {
113 return nil, err
114 }
115 var users []User
116 for rows.Next() {
117 var user User
118 err = rows.Scan(&user.Username, &user.Email, &user.Active, &user.Admin, &user.CreatedAt, &user.Reference)
119 if err != nil {
120 return nil, err
121 }
122 users = append(users, user)
123 }
124 return users, nil
125}
126
127func getIndexFiles(admin bool) ([]*File, error) { // cache this function
128 result := []*File{}
129 err := filepath.Walk(c.FilesDirectory, func(thepath string, info os.FileInfo, err error) error {
130 if err != nil {
131 log.Printf("Failure accessing a path %q: %v\n", thepath, err)
132 return err // think about
133 }
134 if !admin && info.IsDir() && info.Name() == HiddenFolder {
135 return filepath.SkipDir
136 }
137 // make this do what it should
138 if !info.IsDir() {
139 res := fileFromPath(thepath)
140 result = append(result, &res)
141 }
142 return nil
143 })
144 if err != nil {
145 return nil, err
146 }
147 sort.Slice(result, func(i, j int) bool {
148 return result[i].UpdatedTime.After(result[j].UpdatedTime)
149 })
150 if len(result) > 35 {
151 result = result[:35]
152 }
153 return result, nil
154} // todo clean up paths
155
156func getMyFilesRecursive(p string, creator string) ([]File, error) {
157 result := []File{}
158 files, err := ioutil.ReadDir(p)
159 if err != nil {
160 return nil, err
161 }
162 for _, file := range files {
163 fullPath := path.Join(p, file.Name())
164 f := fileFromPath(fullPath)
165 if file.IsDir() {
166 f.Children, err = getMyFilesRecursive(path.Join(p, file.Name()), creator)
167 }
168 result = append(result, f)
169 }
170 return result, nil
171}
172
173func createTablesIfDNE() {
174 _, err := DB.Exec(`CREATE TABLE IF NOT EXISTS user (
175 id INTEGER PRIMARY KEY NOT NULL,
176 username TEXT NOT NULL UNIQUE,
177 email TEXT NOT NULL UNIQUE,
178 password_hash TEXT NOT NULL,
179 reference TEXT NOT NULL default "",
180 active boolean NOT NULL DEFAULT false,
181 admin boolean NOT NULL DEFAULT false,
182 created_at INTEGER DEFAULT (strftime('%s', 'now')),
183 domain TEXT,
184 domain_enabled BOOLEAN NOT NULL DEFAULT false
185);
186
187CREATE TABLE IF NOT EXISTS cookie_key (
188 value TEXT NOT NULL
189);`)
190 if err != nil {
191 log.Fatal(err)
192 }
193}
194
195// Generate a cryptographically secure key for the cookie store
196func generateCookieKeyIfDNE() []byte {
197 rows, err := DB.Query("SELECT value FROM cookie_key LIMIT 1")
198 defer rows.Close()
199 if err != nil {
200 log.Fatal(err)
201 }
202 if rows.Next() {
203 var cookie []byte
204 err := rows.Scan(&cookie)
205 if err != nil {
206 log.Fatal(err)
207 }
208 return cookie
209 } else {
210 k := make([]byte, 32)
211 _, err := io.ReadFull(rand.Reader, k)
212 if err != nil {
213 log.Fatal(err)
214 }
215 _, err = DB.Exec("insert into cookie_key values (?)", k)
216 if err != nil {
217 log.Fatal(err)
218 }
219 return k
220 }
221}