Passworded pastes are here.
This commit is contained in:
		| @@ -1,5 +1,5 @@ | ||||
| // Code generated by fileb0x at "2018-05-01 23:06:19.605611358 +0500 +05 m=+0.029101680" from config file "fileb0x.yml" DO NOT EDIT. | ||||
| // modification hash(397d57216a6c1e49feba398620b3b1d5.e30269e2254cb92c4231bb47f2cedf3a) | ||||
| // Code generated by fileb0x at "2018-05-18 22:25:13.180720675 +0500 +05 m=+0.030971779" from config file "fileb0x.yml" DO NOT EDIT. | ||||
| // modification hash(1679c5529785a2e624071b2679319ecb.608888160ddb195ed89fce5ab290ff92) | ||||
|  | ||||
| package static | ||||
|  | ||||
|   | ||||
										
											
												File diff suppressed because one or more lines are too long
											
										
									
								
							
							
								
								
									
										35
									
								
								api/http/static/b0xfile__passworded_paste_verify.html.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										35
									
								
								api/http/static/b0xfile__passworded_paste_verify.html.go
									
									
									
									
									
										Normal file
									
								
							
										
											
												File diff suppressed because one or more lines are too long
											
										
									
								
							
										
											
												File diff suppressed because one or more lines are too long
											
										
									
								
							| @@ -1,5 +1,5 @@ | ||||
| // Code generaTed by fileb0x at "2018-05-01 18:35:23.707239688 +0500 +05 m=+0.052534784" from config file "fileb0x.yml" DO NOT EDIT. | ||||
| // modified(2018-05-01 18:35:19.361392967 +0500 +05) | ||||
| // Code generaTed by fileb0x at "2018-05-18 22:25:13.191256649 +0500 +05 m=+0.041507879" from config file "fileb0x.yml" DO NOT EDIT. | ||||
| // modified(2018-05-18 22:17:55.447214662 +0500 +05) | ||||
| // original path: assets/pastelist_list.html | ||||
|  | ||||
| package static | ||||
| @@ -10,7 +10,7 @@ import ( | ||||
| ) | ||||
|  | ||||
| // FilePastelistListHTML is "/pastelist_list.html" | ||||
| var FilePastelistListHTML = []byte("\x3c\x21\x44\x4f\x43\x54\x59\x50\x45\x20\x68\x74\x6d\x6c\x3e\x0a\x3c\x68\x74\x6d\x6c\x3e\x0a\x0a\x3c\x68\x65\x61\x64\x3e\x0a\x20\x20\x20\x20\x3c\x6d\x65\x74\x61\x20\x63\x68\x61\x72\x73\x65\x74\x3d\x22\x75\x74\x66\x2d\x38\x22\x3e\x0a\x20\x20\x20\x20\x3c\x6d\x65\x74\x61\x20\x6e\x61\x6d\x65\x3d\x22\x76\x69\x65\x77\x70\x6f\x72\x74\x22\x20\x63\x6f\x6e\x74\x65\x6e\x74\x3d\x22\x77\x69\x64\x74\x68\x3d\x64\x65\x76\x69\x63\x65\x2d\x77\x69\x64\x74\x68\x2c\x20\x69\x6e\x69\x74\x69\x61\x6c\x2d\x73\x63\x61\x6c\x65\x3d\x31\x22\x3e\x0a\x20\x20\x20\x20\x3c\x74\x69\x74\x6c\x65\x3e\x46\x61\x73\x74\x20\x50\x61\x73\x74\x65\x20\x42\x69\x6e\x20\x2d\x20\x45\x52\x52\x4f\x52\x21\x3c\x2f\x74\x69\x74\x6c\x65\x3e\x0a\x20\x20\x20\x20\x3c\x6c\x69\x6e\x6b\x20\x72\x65\x6c\x3d\x22\x73\x74\x79\x6c\x65\x73\x68\x65\x65\x74\x22\x20\x68\x72\x65\x66\x3d\x22\x2f\x73\x74\x61\x74\x69\x63\x2f\x63\x73\x73\x2f\x62\x75\x6c\x6d\x61\x2d\x30\x2e\x37\x2e\x30\x2e\x6d\x69\x6e\x2e\x63\x73\x73\x22\x3e\x0a\x20\x20\x20\x20\x3c\x73\x63\x72\x69\x70\x74\x20\x64\x65\x66\x65\x72\x20\x73\x72\x63\x3d\x22\x2f\x73\x74\x61\x74\x69\x63\x2f\x6a\x73\x2f\x66\x6f\x6e\x74\x61\x77\x65\x73\x6f\x6d\x65\x2d\x35\x2e\x30\x2e\x37\x2e\x6a\x73\x22\x3e\x3c\x2f\x73\x63\x72\x69\x70\x74\x3e\x0a\x20\x20\x20\x20\x3c\x6c\x69\x6e\x6b\x20\x72\x65\x6c\x3d\x22\x73\x74\x79\x6c\x65\x73\x68\x65\x65\x74\x22\x20\x68\x72\x65\x66\x3d\x22\x2f\x73\x74\x61\x74\x69\x63\x2f\x63\x73\x73\x2f\x73\x74\x79\x6c\x65\x2e\x63\x73\x73\x22\x3e\x0a\x3c\x2f\x68\x65\x61\x64\x3e\x0a\x0a\x3c\x62\x6f\x64\x79\x3e\x0a\x20\x20\x20\x20\x3c\x6e\x61\x76\x20\x63\x6c\x61\x73\x73\x3d\x22\x6e\x61\x76\x62\x61\x72\x20\x69\x73\x2d\x64\x61\x72\x6b\x22\x3e\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x3c\x64\x69\x76\x20\x63\x6c\x61\x73\x73\x3d\x22\x6e\x61\x76\x62\x61\x72\x2d\x62\x72\x61\x6e\x64\x22\x3e\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x3c\x61\x20\x63\x6c\x61\x73\x73\x3d\x22\x6e\x61\x76\x62\x61\x72\x2d\x69\x74\x65\x6d\x22\x20\x68\x72\x65\x66\x3d\x22\x2f\x22\x3e\x46\x61\x73\x74\x20\x50\x61\x73\x74\x65\x20\x42\x69\x6e\x3c\x2f\x61\x3e\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x3c\x61\x20\x63\x6c\x61\x73\x73\x3d\x22\x6e\x61\x76\x62\x61\x72\x2d\x69\x74\x65\x6d\x22\x20\x68\x72\x65\x66\x3d\x22\x2f\x70\x61\x73\x74\x65\x73\x2f\x22\x3e\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x50\x61\x73\x74\x65\x73\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x3c\x2f\x61\x3e\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x3c\x64\x69\x76\x20\x63\x6c\x61\x73\x73\x3d\x22\x6e\x61\x76\x62\x61\x72\x2d\x62\x75\x72\x67\x65\x72\x20\x62\x75\x72\x67\x65\x72\x22\x20\x64\x61\x74\x61\x2d\x74\x61\x72\x67\x65\x74\x3d\x22\x6e\x61\x76\x62\x61\x72\x49\x74\x65\x6d\x73\x22\x3e\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x3c\x73\x70\x61\x6e\x3e\x3c\x2f\x73\x70\x61\x6e\x3e\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x3c\x73\x70\x61\x6e\x3e\x3c\x2f\x73\x70\x61\x6e\x3e\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x3c\x73\x70\x61\x6e\x3e\x3c\x2f\x73\x70\x61\x6e\x3e\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x3c\x2f\x64\x69\x76\x3e\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x3c\x2f\x64\x69\x76\x3e\x0a\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x3c\x64\x69\x76\x20\x69\x64\x3d\x22\x6e\x61\x76\x62\x61\x72\x49\x74\x65\x6d\x73\x22\x20\x63\x6c\x61\x73\x73\x3d\x22\x6e\x61\x76\x62\x61\x72\x2d\x6d\x65\x6e\x75\x22\x3e\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x3c\x64\x69\x76\x20\x63\x6c\x61\x73\x73\x3d\x22\x6e\x61\x76\x62\x61\x72\x2d\x73\x74\x61\x72\x74\x22\x3e\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x3c\x2f\x64\x69\x76\x3e\x0a\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x3c\x64\x69\x76\x20\x63\x6c\x61\x73\x73\x3d\x22\x6e\x61\x76\x62\x61\x72\x2d\x65\x6e\x64\x22\x3e\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x3c\x2f\x64\x69\x76\x3e\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x3c\x2f\x64\x69\x76\x3e\x0a\x20\x20\x20\x20\x3c\x2f\x6e\x61\x76\x3e\x0a\x20\x20\x20\x20\x3c\x73\x65\x63\x74\x69\x6f\x6e\x20\x63\x6c\x61\x73\x73\x3d\x22\x73\x65\x63\x74\x69\x6f\x6e\x22\x3e\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x3c\x64\x69\x76\x3e\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x7b\x70\x61\x67\x69\x6e\x61\x74\x69\x6f\x6e\x7d\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x3c\x2f\x64\x69\x76\x3e\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x3c\x64\x69\x76\x3e\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x7b\x70\x61\x73\x74\x65\x73\x7d\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x3c\x2f\x64\x69\x76\x3e\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x3c\x64\x69\x76\x3e\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x7b\x70\x61\x67\x69\x6e\x61\x74\x69\x6f\x6e\x7d\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x3c\x2f\x64\x69\x76\x3e\x0a\x20\x20\x20\x20\x3c\x2f\x73\x65\x63\x74\x69\x6f\x6e\x3e\x0a\x3c\x2f\x62\x6f\x64\x79\x3e\x0a\x0a\x3c\x2f\x68\x74\x6d\x6c\x3e") | ||||
| var FilePastelistListHTML = []byte("\x3c\x21\x44\x4f\x43\x54\x59\x50\x45\x20\x68\x74\x6d\x6c\x3e\x0a\x3c\x68\x74\x6d\x6c\x3e\x0a\x0a\x3c\x68\x65\x61\x64\x3e\x0a\x20\x20\x20\x20\x3c\x6d\x65\x74\x61\x20\x63\x68\x61\x72\x73\x65\x74\x3d\x22\x75\x74\x66\x2d\x38\x22\x3e\x0a\x20\x20\x20\x20\x3c\x6d\x65\x74\x61\x20\x6e\x61\x6d\x65\x3d\x22\x76\x69\x65\x77\x70\x6f\x72\x74\x22\x20\x63\x6f\x6e\x74\x65\x6e\x74\x3d\x22\x77\x69\x64\x74\x68\x3d\x64\x65\x76\x69\x63\x65\x2d\x77\x69\x64\x74\x68\x2c\x20\x69\x6e\x69\x74\x69\x61\x6c\x2d\x73\x63\x61\x6c\x65\x3d\x31\x22\x3e\x0a\x20\x20\x20\x20\x3c\x74\x69\x74\x6c\x65\x3e\x46\x61\x73\x74\x20\x50\x61\x73\x74\x65\x20\x42\x69\x6e\x20\x2d\x20\x50\x61\x73\x74\x65\x73\x3c\x2f\x74\x69\x74\x6c\x65\x3e\x0a\x20\x20\x20\x20\x3c\x6c\x69\x6e\x6b\x20\x72\x65\x6c\x3d\x22\x73\x74\x79\x6c\x65\x73\x68\x65\x65\x74\x22\x20\x68\x72\x65\x66\x3d\x22\x2f\x73\x74\x61\x74\x69\x63\x2f\x63\x73\x73\x2f\x62\x75\x6c\x6d\x61\x2d\x30\x2e\x37\x2e\x30\x2e\x6d\x69\x6e\x2e\x63\x73\x73\x22\x3e\x0a\x20\x20\x20\x20\x3c\x73\x63\x72\x69\x70\x74\x20\x64\x65\x66\x65\x72\x20\x73\x72\x63\x3d\x22\x2f\x73\x74\x61\x74\x69\x63\x2f\x6a\x73\x2f\x66\x6f\x6e\x74\x61\x77\x65\x73\x6f\x6d\x65\x2d\x35\x2e\x30\x2e\x37\x2e\x6a\x73\x22\x3e\x3c\x2f\x73\x63\x72\x69\x70\x74\x3e\x0a\x20\x20\x20\x20\x3c\x6c\x69\x6e\x6b\x20\x72\x65\x6c\x3d\x22\x73\x74\x79\x6c\x65\x73\x68\x65\x65\x74\x22\x20\x68\x72\x65\x66\x3d\x22\x2f\x73\x74\x61\x74\x69\x63\x2f\x63\x73\x73\x2f\x73\x74\x79\x6c\x65\x2e\x63\x73\x73\x22\x3e\x0a\x3c\x2f\x68\x65\x61\x64\x3e\x0a\x0a\x3c\x62\x6f\x64\x79\x3e\x0a\x20\x20\x20\x20\x3c\x6e\x61\x76\x20\x63\x6c\x61\x73\x73\x3d\x22\x6e\x61\x76\x62\x61\x72\x20\x69\x73\x2d\x64\x61\x72\x6b\x22\x3e\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x3c\x64\x69\x76\x20\x63\x6c\x61\x73\x73\x3d\x22\x6e\x61\x76\x62\x61\x72\x2d\x62\x72\x61\x6e\x64\x22\x3e\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x3c\x61\x20\x63\x6c\x61\x73\x73\x3d\x22\x6e\x61\x76\x62\x61\x72\x2d\x69\x74\x65\x6d\x22\x20\x68\x72\x65\x66\x3d\x22\x2f\x22\x3e\x46\x61\x73\x74\x20\x50\x61\x73\x74\x65\x20\x42\x69\x6e\x3c\x2f\x61\x3e\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x3c\x61\x20\x63\x6c\x61\x73\x73\x3d\x22\x6e\x61\x76\x62\x61\x72\x2d\x69\x74\x65\x6d\x22\x20\x68\x72\x65\x66\x3d\x22\x2f\x70\x61\x73\x74\x65\x73\x2f\x22\x3e\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x50\x61\x73\x74\x65\x73\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x3c\x2f\x61\x3e\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x3c\x64\x69\x76\x20\x63\x6c\x61\x73\x73\x3d\x22\x6e\x61\x76\x62\x61\x72\x2d\x62\x75\x72\x67\x65\x72\x20\x62\x75\x72\x67\x65\x72\x22\x20\x64\x61\x74\x61\x2d\x74\x61\x72\x67\x65\x74\x3d\x22\x6e\x61\x76\x62\x61\x72\x49\x74\x65\x6d\x73\x22\x3e\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x3c\x73\x70\x61\x6e\x3e\x3c\x2f\x73\x70\x61\x6e\x3e\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x3c\x73\x70\x61\x6e\x3e\x3c\x2f\x73\x70\x61\x6e\x3e\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x3c\x73\x70\x61\x6e\x3e\x3c\x2f\x73\x70\x61\x6e\x3e\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x3c\x2f\x64\x69\x76\x3e\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x3c\x2f\x64\x69\x76\x3e\x0a\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x3c\x64\x69\x76\x20\x69\x64\x3d\x22\x6e\x61\x76\x62\x61\x72\x49\x74\x65\x6d\x73\x22\x20\x63\x6c\x61\x73\x73\x3d\x22\x6e\x61\x76\x62\x61\x72\x2d\x6d\x65\x6e\x75\x22\x3e\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x3c\x64\x69\x76\x20\x63\x6c\x61\x73\x73\x3d\x22\x6e\x61\x76\x62\x61\x72\x2d\x73\x74\x61\x72\x74\x22\x3e\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x3c\x2f\x64\x69\x76\x3e\x0a\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x3c\x64\x69\x76\x20\x63\x6c\x61\x73\x73\x3d\x22\x6e\x61\x76\x62\x61\x72\x2d\x65\x6e\x64\x22\x3e\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x3c\x2f\x64\x69\x76\x3e\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x3c\x2f\x64\x69\x76\x3e\x0a\x20\x20\x20\x20\x3c\x2f\x6e\x61\x76\x3e\x0a\x20\x20\x20\x20\x3c\x73\x65\x63\x74\x69\x6f\x6e\x20\x63\x6c\x61\x73\x73\x3d\x22\x73\x65\x63\x74\x69\x6f\x6e\x22\x3e\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x3c\x64\x69\x76\x3e\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x7b\x70\x61\x67\x69\x6e\x61\x74\x69\x6f\x6e\x7d\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x3c\x2f\x64\x69\x76\x3e\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x3c\x64\x69\x76\x3e\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x7b\x70\x61\x73\x74\x65\x73\x7d\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x3c\x2f\x64\x69\x76\x3e\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x3c\x64\x69\x76\x3e\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x7b\x70\x61\x67\x69\x6e\x61\x74\x69\x6f\x6e\x7d\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x3c\x2f\x64\x69\x76\x3e\x0a\x20\x20\x20\x20\x3c\x2f\x73\x65\x63\x74\x69\x6f\x6e\x3e\x0a\x3c\x2f\x62\x6f\x64\x79\x3e\x0a\x0a\x3c\x2f\x68\x74\x6d\x6c\x3e") | ||||
|  | ||||
| func init() { | ||||
|    | ||||
|   | ||||
| @@ -73,11 +73,19 @@ | ||||
|                             </div> | ||||
|                         </div> | ||||
|                     </div> | ||||
|                     <div class="field tooltip is-tooltip-bottom is-tooltip-multiline" data-tooltip="Should this paste be accessible only with special URL and not shown in pastes list?"> | ||||
|                     <div class="field tooltip is-tooltip-bottom is-tooltip-multiline" data-tooltip="Should this paste be accessible only with special URL and not shown in pastes list? WARNING: If you'll enter password into 'Password for paste' field this checkbox will be assumed as checked!"> | ||||
|                         <label class="checkbox"> | ||||
|                             <input type="checkbox" name="paste-private" id="paste-private"> Private paste with unique URL? | ||||
|                         </label> | ||||
|                     </div> | ||||
|                     <div>OR</div> | ||||
|                     <div class="field tooltip is-tooltip-bottom is-tooltip-multiline" data-tooltip="If you'll enter password here - 'Private | ||||
|                         paste with unique URL' checkbox will be assumed as checked."> | ||||
|                         <label for="paste-password">Password for paste:</label> | ||||
|                         <div class="control"> | ||||
|                             <input class="input" type="text" placeholder="Enter password." name="paste-password" id="paste-password"> | ||||
|                         </div> | ||||
|                     </div> | ||||
|                     <div class="field"> | ||||
|                         <label for="paste-language">Language:</label> | ||||
|                         <div class="control"> | ||||
|   | ||||
							
								
								
									
										69
									
								
								assets/passworded_paste_verify.html
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										69
									
								
								assets/passworded_paste_verify.html
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,69 @@ | ||||
| <!DOCTYPE html> | ||||
| <html> | ||||
|  | ||||
| <head> | ||||
|     <meta charset="utf-8"> | ||||
|     <meta name="viewport" content="width=device-width, initial-scale=1"> | ||||
|     <title>Fast Paste Bin - Paste is protected with password</title> | ||||
|     <link rel="stylesheet" href="/static/css/bulma-0.7.0.min.css"> | ||||
|     <script defer src="/static/js/fontawesome-5.0.7.js"></script> | ||||
|     <link rel="stylesheet" href="/static/css/style.css"> | ||||
| </head> | ||||
|  | ||||
| <body> | ||||
|     <nav class="navbar is-dark"> | ||||
|         <div class="navbar-brand"> | ||||
|             <a class="navbar-item" href="/">Fast Paste Bin</a> | ||||
|             <a class="navbar-item" href="/pastes/"> | ||||
|                 Pastes | ||||
|             </a> | ||||
|             <div class="navbar-burger burger" data-target="navbarItems"> | ||||
|                 <span></span> | ||||
|                 <span></span> | ||||
|                 <span></span> | ||||
|             </div> | ||||
|         </div> | ||||
|  | ||||
|         <div id="navbarItems" class="navbar-menu"> | ||||
|             <div class="navbar-start"> | ||||
|             </div> | ||||
|  | ||||
|             <div class="navbar-end"> | ||||
|             </div> | ||||
|         </div> | ||||
|     </nav> | ||||
|     <section class="section"> | ||||
|         <div class="content"> | ||||
|             <div class="columns"> | ||||
|                 <div class="column is-4 is-offset-4"> | ||||
|                     <form action="/paste/{pasteID}/{pasteTimestamp}/verify" method="POST" autocomplete="off"> | ||||
|                         <div class="card"> | ||||
|                             <header class="card-header"> | ||||
|                                 <p class="card-header-title"> | ||||
|                                     This paste is protected with password | ||||
|                                 </p> | ||||
|                             </header> | ||||
|                             <div class="card-content"> | ||||
|                                 <div class="content"> | ||||
|                                     <div class="field tooltip is-tooltip-bottom is-tooltip-multiline" data-tooltip="If you'll enter password here - 'Private paste with unique URL' checkbox will be assumed as checked."> | ||||
|                                         <label for="paste-password">Password for paste:</label> | ||||
|                                         <div class="control"> | ||||
|                                             <input class="input" type="text" placeholder="Enter password." name="paste-password" id="paste-password"> | ||||
|                                         </div> | ||||
|                                     </div> | ||||
|                                 </div> | ||||
|                                 <div class="field"> | ||||
|                                     <div class="control"> | ||||
|                                         <input class="button is-success" type="submit" value="Check password!"> | ||||
|                                     </div> | ||||
|                                 </div> | ||||
|                             </div> | ||||
|                         </div> | ||||
|                     </form> | ||||
|                 </div> | ||||
|             </div> | ||||
|         </div> | ||||
|     </section> | ||||
| </body> | ||||
|  | ||||
| </html> | ||||
| @@ -4,7 +4,7 @@ | ||||
| <head> | ||||
|     <meta charset="utf-8"> | ||||
|     <meta name="viewport" content="width=device-width, initial-scale=1"> | ||||
|     <title>Fast Paste Bin - ERROR!</title> | ||||
|     <title>Fast Paste Bin - Paste #{pasteID}</title> | ||||
|     <link rel="stylesheet" href="/static/css/bulma-0.7.0.min.css"> | ||||
|     <script defer src="/static/js/fontawesome-5.0.7.js"></script> | ||||
|     <link rel="stylesheet" href="/static/css/style.css"> | ||||
| @@ -41,6 +41,7 @@ | ||||
|                         <th>Title</th> | ||||
|                         <th>Language</th> | ||||
|                         <th>Pasted on</th> | ||||
|                         <th>Will expire on</th> | ||||
|                         <th>Paste type</th> | ||||
|                     </tr> | ||||
|                 </thead> | ||||
| @@ -50,10 +51,11 @@ | ||||
|                         <td>{pasteTitle}</td> | ||||
|                         <td>{pasteLanguage}</td> | ||||
|                         <td>{pasteDate}</td> | ||||
|                         <td>{pasteExpiration}</td> | ||||
|                         <td>{pasteType}</td> | ||||
|                     </tr> | ||||
|                     <tr> | ||||
|                         <td colspan="5"> | ||||
|                         <td colspan="6"> | ||||
|                             <a class="button" href="/paste/{pasteID}/{pasteTs}raw">View raw</a> | ||||
|                         </td> | ||||
|                     </tr> | ||||
|   | ||||
| @@ -4,7 +4,7 @@ | ||||
| <head> | ||||
|     <meta charset="utf-8"> | ||||
|     <meta name="viewport" content="width=device-width, initial-scale=1"> | ||||
|     <title>Fast Paste Bin - ERROR!</title> | ||||
|     <title>Fast Paste Bin - Pastes</title> | ||||
|     <link rel="stylesheet" href="/static/css/bulma-0.7.0.min.css"> | ||||
|     <script defer src="/static/js/fontawesome-5.0.7.js"></script> | ||||
|     <link rel="stylesheet" href="/static/css/style.css"> | ||||
|   | ||||
							
								
								
									
										58
									
								
								database/migrations/4_passworded_pastes.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										58
									
								
								database/migrations/4_passworded_pastes.go
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,58 @@ | ||||
| // Fast Paste Bin - uberfast and easy-to-use pastebin. | ||||
| // | ||||
| // Copyright (c) 2018, Stanislav N. aka pztrn and Fast Paste Bin | ||||
| // developers. | ||||
| // | ||||
| // Permission is hereby granted, free of charge, to any person obtaining | ||||
| // a copy of this software and associated documentation files (the | ||||
| // "Software"), to deal in the Software without restriction, including | ||||
| // without limitation the rights to use, copy, modify, merge, publish, | ||||
| // distribute, sublicense, and/or sell copies of the Software, and to | ||||
| // permit persons to whom the Software is furnished to do so, subject | ||||
| // to the following conditions: | ||||
| // | ||||
| // The above copyright notice and this permission notice shall be | ||||
| // included in all copies or substantial portions of the Software. | ||||
| // | ||||
| // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, | ||||
| // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF | ||||
| // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. | ||||
| // IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY | ||||
| // CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, | ||||
| // TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE | ||||
| // OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. | ||||
|  | ||||
| package migrations | ||||
|  | ||||
| import ( | ||||
| 	// stdlib | ||||
| 	"database/sql" | ||||
| ) | ||||
|  | ||||
| func PasswordedPastesUp(tx *sql.Tx) error { | ||||
| 	_, err := tx.Exec("ALTER TABLE `pastes` ADD `password` varchar(64) NOT NULL DEFAULT '' COMMENT 'Password for paste (scrypted and sha256ed).'") | ||||
| 	if err != nil { | ||||
| 		return err | ||||
| 	} | ||||
|  | ||||
| 	_, err1 := tx.Exec("ALTER TABLE `pastes` ADD `password_salt` varchar(64) NOT NULL DEFAULT '' COMMENT 'Password salt (sha256ed).'") | ||||
| 	if err1 != nil { | ||||
| 		return err1 | ||||
| 	} | ||||
|  | ||||
| 	return nil | ||||
| } | ||||
|  | ||||
| func PasswordedPastesDown(tx *sql.Tx) error { | ||||
| 	_, err := tx.Exec("ALTER TABLE `pastes` DROP COLUMN `password`") | ||||
| 	if err != nil { | ||||
| 		return err | ||||
| 	} | ||||
|  | ||||
| 	_, err1 := tx.Exec("ALTER TABLE `pastes` DROP COLUMN `password_salt`") | ||||
| 	if err1 != nil { | ||||
| 		return err1 | ||||
| 	} | ||||
|  | ||||
| 	return nil | ||||
| } | ||||
| @@ -100,6 +100,7 @@ custom: | ||||
|     - "assets/pagination_link_current.html" | ||||
|     - "assets/pagination_link.html" | ||||
|     - "assets/pagination.html" | ||||
|     - "assets/passworded_paste_verify.html" | ||||
|     - "assets/paste.html" | ||||
|     - "assets/pastelist_list.html" | ||||
|     - "assets/pastelist_paste.html" | ||||
|   | ||||
| @@ -27,7 +27,6 @@ package pastes | ||||
| import ( | ||||
| 	// stdlib | ||||
| 	"bytes" | ||||
| 	//"html" | ||||
| 	"net/http" | ||||
| 	"regexp" | ||||
| 	"strconv" | ||||
| @@ -97,6 +96,27 @@ func pasteGET(ec echo.Context) error { | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	if paste.Private && paste.Password != "" { | ||||
| 		// Check if cookie for this paste is defined. This means that user | ||||
| 		// previously successfully entered a password. | ||||
| 		cookie, err := ec.Cookie("PASTE-" + strconv.Itoa(pasteID)) | ||||
| 		if err != nil { | ||||
| 			// No cookie, redirect to auth page. | ||||
| 			c.Logger.Info().Msg("Tried to access passworded paste without autorization, redirecting to auth page...") | ||||
| 			return ec.Redirect(http.StatusMovedPermanently, "/paste/"+pasteIDRaw+"/"+ec.Param("timestamp")+"/verify") | ||||
| 		} | ||||
|  | ||||
| 		// Generate cookie value to check. | ||||
| 		cookieValue := paste.GenerateCryptedCookieValue() | ||||
|  | ||||
| 		if cookieValue != cookie.Value { | ||||
| 			c.Logger.Info().Msg("Invalid cookie, redirecting to auth page...") | ||||
| 			return ec.Redirect(http.StatusMovedPermanently, "/paste/"+pasteIDRaw+"/"+ec.Param("timestamp")+"/verify") | ||||
| 		} | ||||
|  | ||||
| 		// If all okay - do nothing :) | ||||
| 	} | ||||
|  | ||||
| 	pasteHTML, err2 := static.ReadFile("paste.html") | ||||
| 	if err2 != nil { | ||||
| 		return ec.String(http.StatusNotFound, "parse.html wasn't found!") | ||||
| @@ -106,6 +126,7 @@ func pasteGET(ec echo.Context) error { | ||||
| 	pasteHTMLAsString := strings.Replace(string(pasteHTML), "{pasteTitle}", paste.Title, 1) | ||||
| 	pasteHTMLAsString = strings.Replace(pasteHTMLAsString, "{pasteID}", strconv.Itoa(paste.ID), -1) | ||||
| 	pasteHTMLAsString = strings.Replace(pasteHTMLAsString, "{pasteDate}", paste.CreatedAt.Format("2006-01-02 @ 15:04:05"), 1) | ||||
| 	pasteHTMLAsString = strings.Replace(pasteHTMLAsString, "{pasteExpiration}", paste.GetExpirationTime().Format("2006-01-02 @ 15:04:05"), 1) | ||||
| 	pasteHTMLAsString = strings.Replace(pasteHTMLAsString, "{pasteLanguage}", paste.Language, 1) | ||||
|  | ||||
| 	if paste.Private { | ||||
| @@ -151,6 +172,99 @@ func pasteGET(ec echo.Context) error { | ||||
| 	return ec.HTML(http.StatusOK, string(pasteHTMLAsString)) | ||||
| } | ||||
|  | ||||
| // GET for "/paste/PASTE_ID/TIMESTAMP/verify" - a password verify page. | ||||
| func pastePasswordedVerifyGet(ec echo.Context) error { | ||||
| 	verifyHTMLRaw, err := static.ReadFile("passworded_paste_verify.html") | ||||
| 	if err != nil { | ||||
| 		return ec.String(http.StatusNotFound, "passworded_paste_verify.html wasn't found!") | ||||
| 	} | ||||
|  | ||||
| 	errhtml, err := static.ReadFile("error.html") | ||||
| 	if err != nil { | ||||
| 		return ec.String(http.StatusNotFound, "error.html wasn't found!") | ||||
| 	} | ||||
|  | ||||
| 	pasteIDRaw := ec.Param("id") | ||||
| 	timestampRaw := ec.Param("timestamp") | ||||
| 	// We already get numbers from string, so we will not check strconv.Atoi() | ||||
| 	// error. | ||||
| 	pasteID, _ := strconv.Atoi(regexInts.FindAllString(pasteIDRaw, 1)[0]) | ||||
|  | ||||
| 	// Get paste. | ||||
| 	paste, err1 := GetByID(pasteID) | ||||
| 	if err1 != nil { | ||||
| 		c.Logger.Error().Msgf("Failed to get paste #%d: %s", pasteID, err1.Error()) | ||||
| 		errhtmlAsString := strings.Replace(string(errhtml), "{error}", "Paste #"+strconv.Itoa(pasteID)+" not found", 1) | ||||
| 		return ec.HTML(http.StatusBadRequest, errhtmlAsString) | ||||
| 	} | ||||
|  | ||||
| 	// Check for auth cookie. If present - redirect to paste. | ||||
| 	cookie, err := ec.Cookie("PASTE-" + strconv.Itoa(pasteID)) | ||||
| 	if err == nil { | ||||
| 		// No cookie, redirect to auth page. | ||||
| 		c.Logger.Debug().Msg("Paste cookie found, checking it...") | ||||
|  | ||||
| 		// Generate cookie value to check. | ||||
| 		cookieValue := paste.GenerateCryptedCookieValue() | ||||
|  | ||||
| 		if cookieValue == cookie.Value { | ||||
| 			c.Logger.Info().Msg("Valid cookie, redirecting to paste page...") | ||||
| 			return ec.Redirect(http.StatusMovedPermanently, "/paste/"+pasteIDRaw+"/"+ec.Param("timestamp")) | ||||
| 		} | ||||
|  | ||||
| 		c.Logger.Debug().Msg("Invalid cookie, showing auth page") | ||||
| 	} | ||||
|  | ||||
| 	verifyHTML := strings.Replace(string(verifyHTMLRaw), "{pasteID}", strconv.Itoa(pasteID), -1) | ||||
| 	verifyHTML = strings.Replace(verifyHTML, "{pasteTimestamp}", timestampRaw, 1) | ||||
|  | ||||
| 	return ec.HTML(http.StatusOK, verifyHTML) | ||||
| } | ||||
|  | ||||
| // POST for "/paste/PASTE_ID/TIMESTAMP/verify" - a password verify page. | ||||
| func pastePasswordedVerifyPost(ec echo.Context) error { | ||||
| 	errhtml, err := static.ReadFile("error.html") | ||||
| 	if err != nil { | ||||
| 		return ec.String(http.StatusNotFound, "error.html wasn't found!") | ||||
| 	} | ||||
|  | ||||
| 	pasteIDRaw := ec.Param("id") | ||||
| 	timestampRaw := ec.Param("timestamp") | ||||
| 	// We already get numbers from string, so we will not check strconv.Atoi() | ||||
| 	// error. | ||||
| 	pasteID, _ := strconv.Atoi(regexInts.FindAllString(pasteIDRaw, 1)[0]) | ||||
| 	c.Logger.Debug().Msgf("Requesting paste #%+v", pasteID) | ||||
|  | ||||
| 	// Get paste. | ||||
| 	paste, err1 := GetByID(pasteID) | ||||
| 	if err1 != nil { | ||||
| 		c.Logger.Error().Msgf("Failed to get paste #%d: %s", pasteID, err1.Error()) | ||||
| 		errhtmlAsString := strings.Replace(string(errhtml), "{error}", "Paste #"+strconv.Itoa(pasteID)+" not found", 1) | ||||
| 		return ec.HTML(http.StatusBadRequest, errhtmlAsString) | ||||
| 	} | ||||
|  | ||||
| 	params, err2 := ec.FormParams() | ||||
| 	if err2 != nil { | ||||
| 		c.Logger.Debug().Msg("No form parameters passed") | ||||
| 		return ec.HTML(http.StatusBadRequest, string(errhtml)) | ||||
| 	} | ||||
|  | ||||
| 	if paste.VerifyPassword(params["paste-password"][0]) { | ||||
| 		// Set cookie that this paste's password is verified and paste | ||||
| 		// can be viewed. | ||||
| 		cookie := new(http.Cookie) | ||||
| 		cookie.Name = "PASTE-" + strconv.Itoa(pasteID) | ||||
| 		cookie.Value = paste.GenerateCryptedCookieValue() | ||||
| 		cookie.Expires = time.Now().Add(24 * time.Hour) | ||||
| 		ec.SetCookie(cookie) | ||||
|  | ||||
| 		return ec.Redirect(http.StatusFound, "/paste/"+strconv.Itoa(pasteID)+"/"+timestampRaw) | ||||
| 	} | ||||
|  | ||||
| 	errhtmlAsString := strings.Replace(string(errhtml), "{error}", "Invalid password. Please, try again.", 1) | ||||
| 	return ec.HTML(http.StatusBadRequest, string(errhtmlAsString)) | ||||
| } | ||||
|  | ||||
| // POST for "/paste/" which will create new paste and redirect to | ||||
| // "/pastes/CREATED_PASTE_ID". | ||||
| func pastePOST(ec echo.Context) error { | ||||
| @@ -227,10 +341,15 @@ func pastePOST(ec echo.Context) error { | ||||
| 	// Private paste? | ||||
| 	paste.Private = false | ||||
| 	privateCheckbox, privateCheckboxFound := params["paste-private"] | ||||
| 	if privateCheckboxFound && privateCheckbox[0] == "on" { | ||||
| 	pastePassword, pastePasswordFound := params["paste-password"] | ||||
| 	if privateCheckboxFound && privateCheckbox[0] == "on" || pastePasswordFound && len(pastePassword[0]) != 0 { | ||||
| 		paste.Private = true | ||||
| 	} | ||||
|  | ||||
| 	if len(pastePassword) != 0 { | ||||
| 		paste.CreatePassword(pastePassword[0]) | ||||
| 	} | ||||
|  | ||||
| 	id, err2 := Save(paste) | ||||
| 	if err2 != nil { | ||||
| 		c.Logger.Debug().Msgf("Failed to save paste: %s", err2.Error()) | ||||
| @@ -284,6 +403,13 @@ func pasteRawGET(ec echo.Context) error { | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	// ToDo: figure out how to handle passworded pastes here. | ||||
| 	// Return error for now. | ||||
| 	if paste.Password != "" { | ||||
| 		c.Logger.Error().Msgf("Cannot render paste #%d as raw: passworded paste. Patches welcome!", pasteID) | ||||
| 		return ec.String(http.StatusBadRequest, "Paste #"+pasteIDRaw+" not found") | ||||
| 	} | ||||
|  | ||||
| 	return ec.String(http.StatusOK, paste.Data) | ||||
| } | ||||
|  | ||||
|   | ||||
| @@ -50,6 +50,9 @@ func New(cc *context.Context) { | ||||
| 	c.Echo.GET("/paste/:id/:timestamp", pasteGET) | ||||
| 	// Show RAW representation of private paste. | ||||
| 	c.Echo.GET("/paste/:id/:timestamp/raw", pasteRawGET) | ||||
| 	// Verify access to passworded paste. | ||||
| 	c.Echo.GET("/paste/:id/:timestamp/verify", pastePasswordedVerifyGet) | ||||
| 	c.Echo.POST("/paste/:id/:timestamp/verify", pastePasswordedVerifyPost) | ||||
|  | ||||
| 	// Pastes list. | ||||
| 	c.Echo.GET("/pastes/", pastesGET) | ||||
|   | ||||
| @@ -26,9 +26,13 @@ package pastes | ||||
|  | ||||
| import ( | ||||
| 	// stdlib | ||||
| 	"crypto/sha256" | ||||
| 	"fmt" | ||||
| 	"math/rand" | ||||
| 	"time" | ||||
|  | ||||
| 	// other | ||||
| 	//"github.com/alecthomas/chroma" | ||||
| 	"golang.org/x/crypto/scrypt" | ||||
| ) | ||||
|  | ||||
| const ( | ||||
| @@ -36,6 +40,8 @@ const ( | ||||
| 	PASTE_KEEP_FOR_HOURS   = 2 | ||||
| 	PASTE_KEEP_FOR_DAYS    = 3 | ||||
| 	PASTE_KEEP_FOR_MONTHS  = 4 | ||||
|  | ||||
| 	charset = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789" | ||||
| ) | ||||
|  | ||||
| var ( | ||||
| @@ -61,6 +67,35 @@ type Paste struct { | ||||
| 	PasswordSalt    string     `db:"password_salt"` | ||||
| } | ||||
|  | ||||
| // CreatePassword creates password for current paste. | ||||
| func (p *Paste) CreatePassword(password string) error { | ||||
| 	// Create salt - random string. | ||||
| 	seededRand := rand.New(rand.NewSource(time.Now().UnixNano())) | ||||
| 	saltBytes := make([]byte, 64) | ||||
| 	for i := range saltBytes { | ||||
| 		saltBytes[i] = charset[seededRand.Intn(len(charset))] | ||||
| 	} | ||||
|  | ||||
| 	saltHashBytes := sha256.Sum256(saltBytes) | ||||
| 	p.PasswordSalt = fmt.Sprintf("%x", saltHashBytes) | ||||
|  | ||||
| 	// Create crypted password and hash it. | ||||
| 	passwordCrypted, err := scrypt.Key([]byte(password), []byte(p.PasswordSalt), 131072, 8, 1, 64) | ||||
| 	if err != nil { | ||||
| 		return err | ||||
| 	} | ||||
| 	passwordHashBytes := sha256.Sum256(passwordCrypted) | ||||
| 	p.Password = fmt.Sprintf("%x", passwordHashBytes) | ||||
|  | ||||
| 	return nil | ||||
| } | ||||
|  | ||||
| // GenerateCryptedCookieValue generates crypted cookie value for paste. | ||||
| func (p *Paste) GenerateCryptedCookieValue() string { | ||||
| 	cookieValueCrypted, _ := scrypt.Key([]byte(p.Password), []byte(p.PasswordSalt), 131072, 8, 1, 64) | ||||
| 	return fmt.Sprintf("%x", sha256.Sum256(cookieValueCrypted)) | ||||
| } | ||||
|  | ||||
| func (p *Paste) GetExpirationTime() time.Time { | ||||
| 	var expirationTime time.Time | ||||
| 	switch p.KeepForUnitType { | ||||
| @@ -88,3 +123,20 @@ func (p *Paste) IsExpired() bool { | ||||
|  | ||||
| 	return false | ||||
| } | ||||
|  | ||||
| // VerifyPassword verifies that provided password is valid. | ||||
| func (p *Paste) VerifyPassword(password string) bool { | ||||
| 	// Create crypted password and hash it. | ||||
| 	passwordCrypted, err := scrypt.Key([]byte(password), []byte(p.PasswordSalt), 131072, 8, 1, 64) | ||||
| 	if err != nil { | ||||
| 		return false | ||||
| 	} | ||||
| 	passwordHashBytes := sha256.Sum256(passwordCrypted) | ||||
| 	providedPassword := fmt.Sprintf("%x", passwordHashBytes) | ||||
|  | ||||
| 	if providedPassword == p.Password { | ||||
| 		return true | ||||
| 	} | ||||
|  | ||||
| 	return false | ||||
| } | ||||
|   | ||||
| @@ -101,7 +101,7 @@ func GetPastesPages() int { | ||||
| // Save saves paste to database and returns it's ID. | ||||
| func Save(p *Paste) (int64, error) { | ||||
| 	dbConn := c.Database.GetDatabaseConnection() | ||||
| 	result, err := dbConn.NamedExec("INSERT INTO `pastes` (title, data, created_at, keep_for, keep_for_unit_type, language, private) VALUES (:title, :data, :created_at, :keep_for, :keep_for_unit_type, :language, :private)", p) | ||||
| 	result, err := dbConn.NamedExec("INSERT INTO `pastes` (title, data, created_at, keep_for, keep_for_unit_type, language, private, password, password_salt) VALUES (:title, :data, :created_at, :keep_for, :keep_for_unit_type, :language, :private, :password, :password_salt)", p) | ||||
| 	if err != nil { | ||||
| 		return 0, err | ||||
| 	} | ||||
|   | ||||
		Reference in New Issue
	
	Block a user