Bladeren bron

baby screaming... working on redirects after posts

bmallred 10 jaren geleden
bovenliggende
commit
71588e4f29
4 gewijzigde bestanden met toevoegingen van 385 en 55 verwijderingen
  1. BIN
      084e0343a0486ff05530df6c705c8bb4
  2. 0 4
      book.html
  3. 55 51
      main.go
  4. 330 0
      resources.go

BIN
084e0343a0486ff05530df6c705c8bb4


+ 0 - 4
book.html

@ -255,9 +255,5 @@
255 255
256 256
    <script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/2.1.3/jquery.min.js"></script>
257 257
    <script src="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.1/js/bootstrap.min.js"></script>
258
    <script>
259
        $(function () {
260
        })
261
    </script>
262 258
</body>
263 259
</html>

+ 55 - 51
main.go

@ -14,6 +14,7 @@ import (
14 14
	"regexp"
15 15
	"strconv"
16 16
	"strings"
17
	"text/template"
17 18
)
18 19
19 20
type Site struct {
@ -25,6 +26,13 @@ type Site struct {
25 26
	NumberOfUpperCase         int    `json:numberOfUpperCase`
26 27
	NumberOfDigits            int    `json:numberOfDigits`
27 28
	Revision                  int    `json:revision`
29
	Password                  string `json:",omitempty"`
30
}
31
32
type Page struct {
33
	Profile    string
34
	Passphrase string
35
	Sites      []Site
28 36
}
29 37
30 38
func main() {
@ -56,17 +64,18 @@ func main() {
56 64
		}
57 65
58 66
		book := getBookname(profile)
59
		sites, err := Read(book, passphrase)
67
		sites, err := read(book, passphrase)
60 68
		if err != nil {
61 69
			http.Error(w, err.Error(), http.StatusInternalServerError)
62 70
			return
63 71
		}
64 72
		sites = append(sites, site)
65
		err = Save(book, passphrase, sites)
73
		err = save(book, passphrase, sites)
66 74
		if err != nil {
67 75
			http.Error(w, err.Error(), http.StatusInternalServerError)
68 76
			return
69 77
		}
78
		http.Redirect(w, r, "/", 200)
70 79
	})
71 80
	http.HandleFunc("/api/update", func(w http.ResponseWriter, r *http.Request) {
72 81
		profile := r.FormValue("profile")
@ -92,17 +101,18 @@ func main() {
92 101
		} else if cmd == "update" {
93 102
			if newPassphrase != confirmPassphrase {
94 103
			}
95
			sites, err := Read(book, passphrase)
104
			sites, err := read(book, passphrase)
96 105
			if err != nil {
97 106
				http.Error(w, err.Error(), http.StatusInternalServerError)
98 107
				return
99 108
			}
100
			err = Save(book, newPassphrase, sites)
109
			err = save(book, newPassphrase, sites)
101 110
			if err != nil {
102 111
				http.Error(w, err.Error(), http.StatusInternalServerError)
103 112
				return
104 113
			}
105 114
		}
115
		http.Redirect(w, r, "/", 200)
106 116
	})
107 117
	http.HandleFunc("/api/refresh", func(w http.ResponseWriter, r *http.Request) {
108 118
		profile := r.FormValue("profile")
@ -116,7 +126,7 @@ func main() {
116 126
117 127
		// Update the revision number and generate a new password
118 128
		book := getBookname(profile)
119
		sites, err := Read(book, passphrase)
129
		sites, err := read(book, passphrase)
120 130
		if err != nil {
121 131
			http.Error(w, err.Error(), http.StatusInternalServerError)
122 132
			return
@ -127,11 +137,12 @@ func main() {
127 137
				break
128 138
			}
129 139
		}
130
		err = Save(book, passphrase, sites)
140
		err = save(book, passphrase, sites)
131 141
		if err != nil {
132 142
			http.Error(w, err.Error(), http.StatusInternalServerError)
133 143
			return
134 144
		}
145
		http.Redirect(w, r, "/", 200)
135 146
	})
136 147
	http.HandleFunc("/api/remove", func(w http.ResponseWriter, r *http.Request) {
137 148
		profile := r.FormValue("profile")
@ -145,7 +156,7 @@ func main() {
145 156
146 157
		// Remove the site from our book and save it
147 158
		book := getBookname(profile)
148
		sites, err := Read(book, passphrase)
159
		sites, err := read(book, passphrase)
149 160
		if err != nil {
150 161
			http.Error(w, err.Error(), http.StatusInternalServerError)
151 162
			return
@ -156,60 +167,53 @@ func main() {
156 167
				break
157 168
			}
158 169
		}
159
		err = Save(book, passphrase, sites)
170
		err = save(book, passphrase, sites)
160 171
		if err != nil {
161 172
			http.Error(w, err.Error(), http.StatusInternalServerError)
162 173
			return
163 174
		}
175
		http.Redirect(w, r, "/", 200)
164 176
	})
165 177
166 178
	http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
167 179
		profile := r.FormValue("profile")
168 180
		passphrase := r.FormValue("p")
169
		//path := strings.TrimPrefix(r.URL.Path, "/")
170 181
171 182
		if profile == "" || passphrase == "" {
172
			// Index
173
			page, err := ioutil.ReadFile("index.html")
183
			fmt.Fprintf(w, templateIndex)
184
		} else {
185
			book := getBookname(profile)
186
			sites, err := read(book, passphrase)
174 187
			if err != nil {
175
				http.NotFound(w, r)
188
				http.Error(w, err.Error(), http.StatusInternalServerError)
176 189
				return
177 190
			}
191
			for _, s := range sites {
192
				p, err := generatePassphrase(profile, passphrase, s)
193
				if err != nil {
194
				}
195
				s.Password = fmt.Sprintf("%s", string(p))
196
			}
178 197
179
			fmt.Fprintf(w, string(page))
180
		} else {
181
			// A passphrase has been entered
182
			page, err := ioutil.ReadFile("book.html")
198
			page := Page{
199
				Profile:    profile,
200
				Passphrase: passphrase,
201
				Sites:      sites,
202
			}
203
204
			t := template.Must(template.New("book").Parse(templateBook))
205
			err = t.Execute(w, page)
183 206
			if err != nil {
184
				http.NotFound(w, r)
207
				http.Error(w, err.Error(), http.StatusInternalServerError)
185 208
				return
186 209
			}
187
188
			fmt.Fprintf(w, string(page))
189 210
		}
190 211
	})
191 212
192 213
	log.Fatal(http.ListenAndServe("localhost:8080", nil))
193
194
	//execDir, err := filepath.Abs(filepath.Dir(os.Args[0]))
195
	//if err != nil {
196
	//	log.Fatal(err)
197
	//}
198
199
	//file := filepath.Join(execDir, "enigma.safe")
200
	//sites, err := Read(file)
201
	//if err != nil {
202
	//	log.Fatal(err)
203
	//}
204
	//log.Println(sites)
205
206
	//err = Save(file, sites)
207
	//if err != nil {
208
	//	log.Fatal(err)
209
	//}
210 214
}
211 215
212
func Save(file, passphrase string, sites []Site) error {
216
func save(file, passphrase string, sites []Site) error {
213 217
	// If the file doesn't exist then create it
214 218
	if _, err := os.Stat(file); os.IsNotExist(err) {
215 219
		_, err = os.Create(file)
@ -225,56 +229,56 @@ func Save(file, passphrase string, sites []Site) error {
225 229
	}
226 230
227 231
	// Compress the contents
228
	buffer := bytes.NewBuffer(b)
229
	gzipWriter := gzip.NewWriter(buffer)
232
	var buffer bytes.Buffer
233
	gzip := gzip.NewWriter(&buffer)
230 234
	if err != nil {
231 235
		return err
232 236
	}
233
	defer gzipWriter.Close()
237
	gzip.Write(b)
238
	gzip.Close()
239
234 240
	// Write to the file
235 241
	fi, err := os.OpenFile(file, os.O_WRONLY, 0666)
236 242
	if err != nil {
237 243
		return err
238 244
	}
239
	defer fi.Close()
240 245
	_, err = fi.Write(buffer.Bytes())
241 246
	if err != nil {
242 247
		return err
243 248
	}
249
	fi.Close()
244 250
245 251
	return nil
246 252
}
247 253
248 254
// Read the password book
249
func Read(file, passphrase string) ([]Site, error) {
255
func read(file, passphrase string) ([]Site, error) {
250 256
	// If the file doesn't exist yet no worries
251 257
	if _, err := os.Stat(file); os.IsNotExist(err) {
252 258
		return []Site{}, nil
253 259
	}
254 260
255 261
	// Bring in the compressed data
256
	log.Println("Reading compressed file")
257
	compressed, err := ioutil.ReadFile(file)
262
	fi, err := os.Open(file)
258 263
	if err != nil {
259 264
		return nil, err
260 265
	}
261 266
262 267
	// Decompress the file contents
263
	log.Println("Decompressing")
264
	buffer := bytes.NewBuffer(compressed)
265
	gzipReader, err := gzip.NewReader(buffer)
268
	gzip, err := gzip.NewReader(fi)
266 269
	if err != nil {
267 270
		return nil, err
268 271
	}
269
	defer gzipReader.Close()
272
	decompressed, err := ioutil.ReadAll(gzip)
273
	gzip.Close()
270 274
271 275
	// Unmarshal the JSON information
272
	log.Println("Unmarshal")
273 276
	var sites []Site
274
	err = json.Unmarshal(buffer.Bytes(), &sites)
277
	err = json.Unmarshal(decompressed, &sites)
275 278
	if err != nil {
276 279
		return nil, err
277 280
	}
281
	fi.Close()
278 282
279 283
	return sites, nil
280 284
}
@ -283,7 +287,7 @@ func Read(file, passphrase string) ([]Site, error) {
283 287
func getBookname(profile string) string {
284 288
	hash := md5.New()
285 289
	hash.Write([]byte(profile))
286
	return fmt.Sprintf("%s", string(hash.Sum(nil)))
290
	return fmt.Sprintf("%x", string(hash.Sum(nil)))
287 291
}
288 292
289 293
// Encrypt the password book

+ 330 - 0
resources.go

@ -0,0 +1,330 @@
1
package main
2
3
const (
4
	templateIndex string = `<!doctype html>
5
<html lang="en">
6
<head>
7
    <meta charset="utf-8">
8
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
9
    <meta name="viewport" content="width=device-width, initial-scale=1">
10
11
    <title>Enigma Login</title>
12
13
    <link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.1/css/bootstrap.min.css" />
14
    <link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.1/css/bootstrap-theme.min.css" />
15
    <style type="text/css">
16
        body {
17
            padding-top: 40px;
18
            padding-bottom: 40px;
19
            background-color: #eee;
20
        }
21
22
        .form-signin {
23
            max-width: 330px;
24
            padding: 15px;
25
            margin: 0 auto;
26
        }
27
        .form-signin .form-signin-heading,
28
        .form-signin .checkbox {
29
            margin-bottom: 10px;
30
        }
31
        .form-signin .checkbox {
32
            font-weight: normal;
33
        }
34
        .form-signin .form-control {
35
            position: relative;
36
            height: auto;
37
            -webkit-box-sizing: border-box;
38
            -moz-box-sizing: border-box;
39
            box-sizing: border-box;
40
            padding: 10px;
41
            font-size: 16px;
42
        }
43
        .form-signin .form-control:focus {
44
            z-index: 2;
45
        }
46
        .form-signin input[type="email"] {
47
            margin-bottom: -1px;
48
            border-bottom-right-radius: 0;
49
            border-bottom-left-radius: 0;
50
        }
51
        .form-signin input[type="password"] {
52
            margin-bottom: 10px;
53
            border-top-left-radius: 0;
54
            border-top-right-radius: 0;
55
        }
56
    </style>
57
58
    <!-- HTML5 shim and Respond.js for IE8 support of HTML5 elements and media queries -->
59
    <!-- WARNING: Respond.js doesn't work if you view the page via file:// -->
60
    <!--[if lt IE 9]>
61
        <script src="https://oss.maxcdn.com/html5shiv/3.7.2/html5shiv.min.js"></script>
62
        <script src="https://oss.maxcdn.com/respond/1.4.2/respond.min.js"></script>
63
    <![endif]-->
64
</head>
65
<body>
66
    <div class="container">
67
        <form action="/" method="post" class="form-signin">
68
            <h2 class="form-signin-heading">Please sign in</h2>
69
            <label for="profile" class="sr-only">Email address</label>
70
            <input type="text" id="profile" name="profile" class="form-control" placeholder="Username" required autofocus>
71
            <label for="p" class="sr-only">Password</label>
72
            <input type="password" id="p" name="p" class="form-control" placeholder="Password" required>
73
            <div class="checkbox">
74
                <label>
75
                    <input type="checkbox" value="remember-me"> Remember me
76
                </label>
77
            </div>
78
            <button class="btn btn-lg btn-primary btn-block" type="submit">Sign in</button>
79
        </form>
80
    </div>
81
82
    <script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/2.1.3/jquery.min.js"></script>
83
    <script src="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.1/js/bootstrap.min.js"></script>
84
</body>
85
</html>`
86
87
	templateBook string = `<!doctype html>
88
<html lang="en">
89
<head>
90
    <meta charset="utf-8">
91
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
92
    <meta name="viewport" content="width=device-width, initial-scale=1">
93
94
    <title>Enigma</title>
95
96
    <link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.1/css/bootstrap.min.css" />
97
    <link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.1/css/bootstrap-theme.min.css" />
98
    <style type="text/css">
99
        body {
100
            padding-top: 40px;
101
            padding-bottom: 40px;
102
            background-color: #fff;
103
        }
104
        h2 {
105
            margin-bottom: 1em;
106
        }
107
        td {
108
            text-align: left;
109
            vertical-align: middle !important;
110
        }
111
        .tab-content > .tab-pane {
112
            padding: 1em;
113
        }
114
    </style>
115
116
    <!-- HTML5 shim and Respond.js for IE8 support of HTML5 elements and media queries -->
117
    <!-- WARNING: Respond.js doesn't work if you view the page via file:// -->
118
    <!--[if lt IE 9]>
119
        <script src="https://oss.maxcdn.com/html5shiv/3.7.2/html5shiv.min.js"></script>
120
        <script src="https://oss.maxcdn.com/respond/1.4.2/respond.min.js"></script>
121
    <![endif]-->
122
</head>
123
<body>
124
    <div class="container">
125
        <h1>Enigma</h1>
126
        <h2><small>Your personal password safe and generator</small></h2>
127
128
		{{ $profile := .Profile }}
129
		{{ $passphrase := .Passphrase }}
130
131
        <div role="tabpanel">
132
            <ul class="nav nav-tabs" role="tablist">
133
                <li role="presentation" class="active"><a href="#passwords" aria-controls="passwords" role="tab" data-toggle="tab">Passwords</a></li>
134
                <li role="presentation"><a href="#add" aria-controls="Add" role="tab" data-toggle="tab">Add</a></li>
135
                <li role="presentation"><a href="#settings" aria-controls="settings" role="tab" data-toggle="tab">Settings</a></li>
136
            </ul>
137
            <div class="tab-content">
138
                <div role="tabpanel" class="tab-pane active" id="passwords">
139
                    <table class="table table-striped table-hover">
140
                        <thead>
141
                            <tr>
142
                                <th>Site</th>
143
                                <th>Password</th>
144
                                <th>&nbsp;</th>
145
                            </tr>
146
                        </thead>
147
                        <tbody>
148
							{{ range .Sites }}
149
                            <tr>
150
                                <td>{{ .Host }}</td>
151
                                <td>
152
                                    <button class="btn btn-default btn-xs"><span class="glyphicon glyphicon-share" aria-hidden="true"></span></button>
153
                                    <form class="form form-horizontal" style="display: inline-block;" action="/api/refresh" method="post">
154
                                        <input name="profile" type="hidden" value="{{ $profile }}" />
155
                                        <input name="p" type="hidden" value="{{ $passphrase }}" />
156
                                        <input name="host" type="hidden" value="{{ .Host }}" />
157
                                        <button class="btn btn-default btn-xs"><span class="glyphicon glyphicon-refresh" aria-hidden="true"></span></button>
158
                                    </form>
159
                                    <span>{{ .Password }}</span>
160
                                </td>
161
                                <td class="text-right">
162
                                    <form class="form form-horizontal" action="/api/remove" method="post">
163
                                        <input name="profile" type="hidden" value="{{ $profile }}" />
164
                                        <input name="p" type="hidden" value="{{ $passphrase }}" />
165
                                        <input name="host" type="hidden" value="{{ .Host }}" />
166
                                        <button class="btn btn-default"><span class="glyphicon glyphicon-remove" aria-hidden="true"></span></button>
167
                                    </form>
168
                                </td>
169
                            </tr>
170
							{{ end }}
171
                        </tbody>
172
                    </table>
173
                </div>
174
                <div role="tabpanel" class="tab-pane" id="add">
175
                    <form class="form form-horizontal" action="/api/generate" method="post">
176
						<input name="profile" type="hidden" value="{{ $profile }}" />
177
						<input name="p" type="hidden" value="{{ $passphrase }}" />
178
                        <div class="form-group">
179
                            <label for="host" class="col-xs-3 control-label">Site</label>
180
                            <div class="col-xs-9">
181
                                <input id="host" name="host" type="text" class="form-control" placeholder="gmail.com" />
182
                            </div>
183
                        </div>
184
                        <div class="form-group">
185
                            <label for="minimumLength" class="col-xs-3 control-label">Minimum Length</label>
186
                            <div class="col-xs-3">
187
                                <select id="minimumLength" name="minimumLength" class="form-control">
188
                                    <option value="-1">No Limit</option>
189
                                    <option>1</option>
190
                                    <option>2</option>
191
                                    <option>3</option>
192
                                    <option>4</option>
193
                                    <option>5</option>
194
                                    <option>6</option>
195
                                    <option>7</option>
196
                                    <option>8</option>
197
                                    <option>9</option>
198
                                    <option>10</option>
199
                                </select>
200
                            </div>
201
                        </div>
202
                        <div class="form-group">
203
                            <label for="maximumLength" class="col-xs-3 control-label">Maximum Length</label>
204
                            <div class="col-xs-3">
205
                                <select id="maximumLength" name="maximumLength" class="form-control">
206
                                    <option value="-1">No Limit</option>
207
                                    <option>4</option>
208
                                    <option>5</option>
209
                                    <option>6</option>
210
                                    <option>7</option>
211
                                    <option>8</option>
212
                                    <option>9</option>
213
                                    <option>10</option>
214
                                    <option>11</option>
215
                                    <option>12</option>
216
                                    <option>13</option>
217
                                    <option>14</option>
218
                                    <option>15</option>
219
                                    <option>16</option>
220
                                    <option>17</option>
221
                                    <option>18</option>
222
                                    <option>19</option>
223
                                    <option>20</option>
224
                                </select>
225
                            </div>
226
                        </div>
227
                        <div class="form-group">
228
                            <label for="minimumDigits" class="col-xs-3 control-label">Minimum Digits</label>
229
                            <div class="col-xs-3">
230
                                <select id="minimumDigits" name="minimumLength" class="form-control">
231
                                    <option>0</option>
232
                                    <option>1</option>
233
                                    <option>2</option>
234
                                    <option>3</option>
235
                                    <option>4</option>
236
                                    <option>5</option>
237
                                    <option>6</option>
238
                                    <option>7</option>
239
                                    <option>8</option>
240
                                    <option>9</option>
241
                                    <option>10</option>
242
                                </select>
243
                            </div>
244
                        </div>
245
                        <div class="form-group">
246
                            <label for="minimumUppercase" class="col-xs-3 control-label">Minimum Uppercase</label>
247
                            <div class="col-xs-3">
248
                                <select id="minimumUppercase" name="minimumUppercase" class="form-control">
249
                                    <option>0</option>
250
                                    <option>1</option>
251
                                    <option>2</option>
252
                                    <option>3</option>
253
                                    <option>4</option>
254
                                    <option>5</option>
255
                                    <option>6</option>
256
                                    <option>7</option>
257
                                    <option>8</option>
258
                                    <option>9</option>
259
                                    <option>10</option>
260
                                </select>
261
                            </div>
262
                        </div>
263
                        <div class="form-group">
264
                            <label for="minimumSpecialCharacters" class="col-xs-3 control-label">Minimum Special Characters</label>
265
                            <div class="col-xs-3">
266
                                <select id="minimumSpecialCharacters" name="minimumSpecialCharacters" class="form-control">
267
                                    <option>0</option>
268
                                    <option>1</option>
269
                                    <option>2</option>
270
                                    <option>3</option>
271
                                    <option>4</option>
272
                                    <option>5</option>
273
                                    <option>6</option>
274
                                    <option>7</option>
275
                                    <option>8</option>
276
                                    <option>9</option>
277
                                    <option>10</option>
278
                                </select>
279
                            </div>
280
                        </div>
281
                        <div class="form-group">
282
                            <label for="specialCharacters" class="col-xs-3 control-label">Special Characters</label>
283
                            <div class="col-xs-9">
284
                                <input id="specialCharacters" name="specialCharacters" type="text" class="form-control" value=" !@#$%^&*()_+-=<>,." />
285
                            </div>
286
                        </div>
287
                        <div class="form-group">
288
                            <div class="col-xs-offset-3 col-xs-10">
289
                                <button type="submit" class="btn btn-default">Generate Password</button>
290
                            </div>
291
                        </div>
292
                    </form>
293
                </div>
294
                <div role="tabpanel" class="tab-pane" id="settings">
295
                    <div class="row">
296
                        <form class="form form-horizontal" action="/api/update" method="post">
297
							<input name="profile" type="hidden" value="{{ $profile }}" />
298
							<input name="p" type="hidden" value="{{ $passphrase }}" />
299
                            <div class="form-group">
300
                                <label for="newPassphrase" class="col-xs-3 control-label">New passphrase</label>
301
                                <div class="col-xs-9">
302
                                    <input id="newPassphrase" type="password" class="form-control" placeholder="" />
303
                                </div>
304
                            </div>
305
                            <div class="form-group">
306
                                <label for="confirmPassphrase" class="col-xs-3 control-label">Confirm passphrase</label>
307
                                <div class="col-xs-9">
308
                                    <input id="confirmPassphrase" type="password" class="form-control" placeholder="" />
309
                                </div>
310
                            </div>
311
                            <div class="form-group">
312
                                <div class="col-xs-offset-3 col-xs-6">
313
                                    <button name="cmd" value="update" type="submit" class="btn btn-default">Update Passphrase</button>
314
                                </div>
315
                                <div class="col-xs-3 text-right">
316
                                    <button name="cmd" value="delete" type="submit" class="btn btn-danger">Delete Profile</button>
317
                                </div>
318
                            </div>
319
                        </form>
320
                    </div>
321
                </div>
322
            </div>
323
        </div>
324
    </div>
325
326
    <script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/2.1.3/jquery.min.js"></script>
327
    <script src="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.1/js/bootstrap.min.js"></script>
328
</body>
329
</html>`
330
)