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