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