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 Domain string
81 DomainEnabled bool
82}
83
84func getActiveUserNames() ([]string, error) {
85 rows, err := DB.Query(`SELECT username from user WHERE active is true order by username`)
86 if err != nil {
87 return nil, err
88 }
89 var users []string
90 for rows.Next() {
91 var user string
92 err = rows.Scan(&user)
93 if err != nil {
94 return nil, err
95 }
96 users = append(users, user)
97 }
98
99 return users, nil
100}
101
102var domains map[string]string
103
104func refreshDomainMap() error {
105 domains = make(map[string]string)
106 rows, err := DB.Query(`SELECT domain, username from user WHERE domain != ""`)
107 if err != nil {
108 log.Println(err)
109 return err
110 }
111 for rows.Next() {
112 var domain string
113 var username string
114 err = rows.Scan(&domain, &username)
115 if err != nil {
116 return err
117 }
118 domains[domain] = username
119 }
120 return nil
121}
122
123func getUserByName(username string) (*User, error) {
124 var user User
125 row := DB.QueryRow(`SELECT username, email, active, admin, created_at, reference, domain, domain_enabled from user WHERE username = ?`, username)
126 err := row.Scan(&user.Username, &user.Email, &user.Active, &user.Admin, &user.CreatedAt, &user.Reference, &user.Domain, &user.DomainEnabled)
127 if err != nil {
128 return nil, err
129 }
130 return &user, nil
131}
132
133func getUsers() ([]User, error) {
134 rows, err := DB.Query(`SELECT username, email, active, admin, created_at, reference, domain from user ORDER BY created_at DESC`)
135 if err != nil {
136 return nil, err
137 }
138 var users []User
139 for rows.Next() {
140 var user User
141 err = rows.Scan(&user.Username, &user.Email, &user.Active, &user.Admin, &user.CreatedAt, &user.Reference, &user.Domain)
142 if err != nil {
143 return nil, err
144 }
145 users = append(users, user)
146 }
147 return users, nil
148}
149
150func getIndexFiles(admin bool) ([]*File, error) { // cache this function
151 result := []*File{}
152 err := filepath.Walk(c.FilesDirectory, func(thepath string, info os.FileInfo, err error) error {
153 if err != nil {
154 log.Printf("Failure accessing a path %q: %v\n", thepath, err)
155 return err // think about
156 }
157 if !admin && info.IsDir() && info.Name() == HiddenFolder {
158 return filepath.SkipDir
159 }
160 // make this do what it should
161 if !info.IsDir() {
162 res := fileFromPath(thepath)
163 result = append(result, &res)
164 }
165 return nil
166 })
167 if err != nil {
168 return nil, err
169 }
170 sort.Slice(result, func(i, j int) bool {
171 return result[i].UpdatedTime.After(result[j].UpdatedTime)
172 })
173 if len(result) > 50 {
174 result = result[:50]
175 }
176 return result, nil
177} // todo clean up paths
178
179func getMyFilesRecursive(p string, creator string) ([]File, error) {
180 result := []File{}
181 files, err := ioutil.ReadDir(p)
182 if err != nil {
183 return nil, err
184 }
185 for _, file := range files {
186 fullPath := path.Join(p, file.Name())
187 f := fileFromPath(fullPath)
188 if file.IsDir() {
189 f.Children, err = getMyFilesRecursive(path.Join(p, file.Name()), creator)
190 }
191 result = append(result, f)
192 }
193 return result, nil
194}
195
196func createTablesIfDNE() {
197 _, err := DB.Exec(`CREATE TABLE IF NOT EXISTS user (
198 id INTEGER PRIMARY KEY NOT NULL,
199 username TEXT NOT NULL UNIQUE,
200 email TEXT NOT NULL UNIQUE,
201 password_hash TEXT NOT NULL,
202 reference TEXT NOT NULL default "",
203 active boolean NOT NULL DEFAULT false,
204 admin boolean NOT NULL DEFAULT false,
205 created_at INTEGER DEFAULT (strftime('%s', 'now')),
206 domain TEXT NOT NULL default "",
207 domain_enabled BOOLEAN NOT NULL DEFAULT false
208);
209
210CREATE TABLE IF NOT EXISTS cookie_key (
211 value TEXT NOT NULL
212);`)
213 if err != nil {
214 log.Fatal(err)
215 }
216}
217
218// Generate a cryptographically secure key for the cookie store
219func generateCookieKeyIfDNE() []byte {
220 rows, err := DB.Query("SELECT value FROM cookie_key LIMIT 1")
221 defer rows.Close()
222 if err != nil {
223 log.Fatal(err)
224 }
225 if rows.Next() {
226 var cookie []byte
227 err := rows.Scan(&cookie)
228 if err != nil {
229 log.Fatal(err)
230 }
231 return cookie
232 } else {
233 k := make([]byte, 32)
234 _, err := io.ReadFull(rand.Reader, k)
235 if err != nil {
236 log.Fatal(err)
237 }
238 _, err = DB.Exec("insert into cookie_key values (?)", k)
239 if err != nil {
240 log.Fatal(err)
241 }
242 return k
243 }
244}