mirror of
https://github.com/number571/hes.git
synced 2026-09-12 19:50:01 +05:00
add compile
This commit is contained in:
parent
93ffe80981
commit
bd6f8f4f70
13
.gitignore
vendored
13
.gitignore
vendored
@ -1,6 +1,7 @@
|
||||
client
|
||||
client.exe
|
||||
client.db
|
||||
server
|
||||
server.exe
|
||||
server.db
|
||||
client_*_*
|
||||
server_*_*
|
||||
client.db
|
||||
server.db
|
||||
client
|
||||
server
|
||||
compile
|
||||
|
||||
42
LICENSE
42
LICENSE
@ -1,21 +1,21 @@
|
||||
MIT License
|
||||
|
||||
Copyright (c) 2020 [#571]
|
||||
|
||||
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.
|
||||
MIT License
|
||||
|
||||
Copyright (c) 2020 [#571]
|
||||
|
||||
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.
|
||||
|
||||
22
Makefile
22
Makefile
@ -1,9 +1,13 @@
|
||||
GC=go build
|
||||
GFILES=client.go cdatabase.go cmodels.go csessions.go gconsts.go server.go sdatabase.go sconfig.go
|
||||
.PHONY: default build clean
|
||||
default: build
|
||||
build: $(GFILES)
|
||||
$(GC) client.go gconsts.go cdatabase.go cmodels.go csessions.go
|
||||
$(GC) server.go gconsts.go sdatabase.go sconfig.go
|
||||
clean:
|
||||
rm -f client.db server.db server client
|
||||
CC=gcc
|
||||
GC=go build
|
||||
GFILES=client.go cdatabase.go cmodels.go csessions.go gconsts.go server.go sdatabase.go sconfig.go
|
||||
.PHONY: default build clean
|
||||
default: build
|
||||
build: $(GFILES)
|
||||
$(GC) client.go gconsts.go cdatabase.go cmodels.go csessions.go
|
||||
$(GC) server.go gconsts.go sdatabase.go sconfig.go
|
||||
build_all: compile.c $(GFILES)
|
||||
$(CC) -o compile compile.c
|
||||
./compile
|
||||
clean:
|
||||
rm -f client.db server.db server client compile client_*_* server_*_*
|
||||
|
||||
238
README.md
238
README.md
@ -1,119 +1,119 @@
|
||||
# HES
|
||||
|
||||
> Hidden email service. Version 1.1.10s.
|
||||
|
||||
### Home page
|
||||
<img src="/userside/images/HES1.png" alt="HomePage"/>
|
||||
|
||||
### Characteristics
|
||||
1. End to end encryption;
|
||||
2. Supported tor connections;
|
||||
3. Symmetric algorithm: AES-CBC;
|
||||
4. Asymmetric algorithm: RSA-OAEP, RSA-PSS;
|
||||
5. Hash function: SHA256;
|
||||
|
||||
### Account page
|
||||
<img src="/userside/images/HES4.png" alt="AccountPage"/>
|
||||
|
||||
### Compile and run
|
||||
```
|
||||
$ make
|
||||
> go build client.go gconsts.go cdatabase.go cmodels.go csessions.go
|
||||
> go build server.go gconsts.go sdatabase.go sconfig.go
|
||||
$ ./server -open="localhost:8080" &
|
||||
$ ./client -open="localhost:7545"
|
||||
```
|
||||
|
||||
### List of emails page
|
||||
<img src="/userside/images/HES7.png" alt="ListOfEmailsPage"/>
|
||||
|
||||
### DB and CFG files
|
||||
> Database and config files are creates when the application starts.
|
||||
|
||||
#### Server side db (server.db)
|
||||
```sql
|
||||
/* recv = hash(public_key) */
|
||||
/* hash = hash(data) */
|
||||
/* data = encrypt(email) */
|
||||
CREATE TABLE IF NOT EXISTS emails (
|
||||
id INTEGER,
|
||||
recv VARCHAR(255),
|
||||
hash VARCHAR(255) UNIQUE,
|
||||
data TEXT,
|
||||
addtime DATETIME DEFAULT CURRENT_TIMESTAMP,
|
||||
PRIMARY KEY(id)
|
||||
);
|
||||
```
|
||||
|
||||
#### Server side cfg (server.cfg)
|
||||
```go
|
||||
type CFG struct {
|
||||
Pasw string `json:"pasw"`
|
||||
Conns [][2]string `json:"conns"`
|
||||
}
|
||||
```
|
||||
|
||||
#### Client side db (client.db)
|
||||
```sql
|
||||
/* !key_pasw = hash(password, salt)^25 */
|
||||
/* hashn = hash(nickname) */
|
||||
/* hashp = hash(!key_pasw, nickname) */
|
||||
/* priv = encrypt[!key_pasw](private_key) */
|
||||
CREATE TABLE IF NOT EXISTS users (
|
||||
id INTEGER,
|
||||
f2f BOOLEAN,
|
||||
hashn VARCHAR(255) UNIQUE,
|
||||
hashp VARCHAR(255),
|
||||
salt VARCHAR(255),
|
||||
priv TEXT,
|
||||
PRIMARY KEY(id)
|
||||
);
|
||||
/* hashn = hash(nickname, !key_pasw) */
|
||||
/* hashp = hash(public_key, !key_pasw) */
|
||||
/* name = encrypt[!key_pasw](nickname) */
|
||||
/* publ = encrypt[!key_pasw](public_key) */
|
||||
CREATE TABLE IF NOT EXISTS contacts (
|
||||
id INTEGER,
|
||||
id_user INTEGER,
|
||||
hashn VARCHAR(255) UNIQUE,
|
||||
hashp VARCHAR(255) UNIQUE,
|
||||
name NVARCHAR(255),
|
||||
publ TEXT,
|
||||
PRIMARY KEY(id),
|
||||
FOREIGN KEY(id_user) REFERENCES users(id) ON DELETE CASCADE
|
||||
);
|
||||
/* hash = hash(host, !key_pasw) */
|
||||
/* host = encrypt[!key_pasw](host) */
|
||||
/* pasw = encrypt[!key_pasw](pasw) */
|
||||
CREATE TABLE IF NOT EXISTS connects (
|
||||
id INTEGER,
|
||||
id_user INTEGER,
|
||||
hash VARCHAR(255) UNIQUE,
|
||||
host VARCHAR(255),
|
||||
pasw VARCHAR(255),
|
||||
PRIMARY KEY(id),
|
||||
FOREIGN KEY(id_user) REFERENCES users(id) ON DELETE CASCADE
|
||||
);
|
||||
/* hash = hash(pack_hash, !key_pasw) */
|
||||
/* spubl = encrypt[!key_pasw](public_key) */
|
||||
/* sname = encrypt[!key_pasw](nickname) */
|
||||
/* head = encrypt[!key_pasw](title) */
|
||||
/* body = encrypt[!key_pasw](message) */
|
||||
/* addtime = encrypt[!key_pasw](time_rec) */
|
||||
CREATE TABLE IF NOT EXISTS emails (
|
||||
id INTEGER,
|
||||
id_user INTEGER,
|
||||
deleted BOOLEAN DEFAULT 0,
|
||||
hash VARCHAR(255) UNIQUE,
|
||||
spubl TEXT,
|
||||
sname NVARCHAR(255),
|
||||
head NVARCHAR(255),
|
||||
body TEXT,
|
||||
addtime TEXT,
|
||||
PRIMARY KEY(id),
|
||||
FOREIGN KEY(id_user) REFERENCES users(id) ON DELETE CASCADE
|
||||
);
|
||||
```
|
||||
|
||||
### Email page
|
||||
<img src="/userside/images/HES8.png" alt="EmailPage"/>
|
||||
# HES
|
||||
|
||||
> Hidden email service. Version 1.1.10s.
|
||||
|
||||
### Home page
|
||||
<img src="/userside/images/HES1.png" alt="HomePage"/>
|
||||
|
||||
### Characteristics
|
||||
1. End to end encryption;
|
||||
2. Supported tor connections;
|
||||
3. Symmetric algorithm: AES-CBC;
|
||||
4. Asymmetric algorithm: RSA-OAEP, RSA-PSS;
|
||||
5. Hash function: SHA256;
|
||||
|
||||
### Account page
|
||||
<img src="/userside/images/HES4.png" alt="AccountPage"/>
|
||||
|
||||
### Compile and run
|
||||
```
|
||||
$ make
|
||||
> go build client.go gconsts.go cdatabase.go cmodels.go csessions.go
|
||||
> go build server.go gconsts.go sdatabase.go sconfig.go
|
||||
$ ./server -open="localhost:8080" &
|
||||
$ ./client -open="localhost:7545"
|
||||
```
|
||||
|
||||
### List of emails page
|
||||
<img src="/userside/images/HES7.png" alt="ListOfEmailsPage"/>
|
||||
|
||||
### DB and CFG files
|
||||
> Database and config files are creates when the application starts.
|
||||
|
||||
#### Server side db (server.db)
|
||||
```sql
|
||||
/* recv = hash(public_key) */
|
||||
/* hash = hash(data) */
|
||||
/* data = encrypt(email) */
|
||||
CREATE TABLE IF NOT EXISTS emails (
|
||||
id INTEGER,
|
||||
recv VARCHAR(255),
|
||||
hash VARCHAR(255) UNIQUE,
|
||||
data TEXT,
|
||||
addtime DATETIME DEFAULT CURRENT_TIMESTAMP,
|
||||
PRIMARY KEY(id)
|
||||
);
|
||||
```
|
||||
|
||||
#### Server side cfg (server.cfg)
|
||||
```go
|
||||
type CFG struct {
|
||||
Pasw string `json:"pasw"`
|
||||
Conns [][2]string `json:"conns"`
|
||||
}
|
||||
```
|
||||
|
||||
#### Client side db (client.db)
|
||||
```sql
|
||||
/* !key_pasw = hash(password, salt)^25 */
|
||||
/* hashn = hash(nickname) */
|
||||
/* hashp = hash(!key_pasw, nickname) */
|
||||
/* priv = encrypt[!key_pasw](private_key) */
|
||||
CREATE TABLE IF NOT EXISTS users (
|
||||
id INTEGER,
|
||||
f2f BOOLEAN,
|
||||
hashn VARCHAR(255) UNIQUE,
|
||||
hashp VARCHAR(255),
|
||||
salt VARCHAR(255),
|
||||
priv TEXT,
|
||||
PRIMARY KEY(id)
|
||||
);
|
||||
/* hashn = hash(nickname, !key_pasw) */
|
||||
/* hashp = hash(public_key, !key_pasw) */
|
||||
/* name = encrypt[!key_pasw](nickname) */
|
||||
/* publ = encrypt[!key_pasw](public_key) */
|
||||
CREATE TABLE IF NOT EXISTS contacts (
|
||||
id INTEGER,
|
||||
id_user INTEGER,
|
||||
hashn VARCHAR(255) UNIQUE,
|
||||
hashp VARCHAR(255) UNIQUE,
|
||||
name NVARCHAR(255),
|
||||
publ TEXT,
|
||||
PRIMARY KEY(id),
|
||||
FOREIGN KEY(id_user) REFERENCES users(id) ON DELETE CASCADE
|
||||
);
|
||||
/* hash = hash(host, !key_pasw) */
|
||||
/* host = encrypt[!key_pasw](host) */
|
||||
/* pasw = encrypt[!key_pasw](pasw) */
|
||||
CREATE TABLE IF NOT EXISTS connects (
|
||||
id INTEGER,
|
||||
id_user INTEGER,
|
||||
hash VARCHAR(255) UNIQUE,
|
||||
host VARCHAR(255),
|
||||
pasw VARCHAR(255),
|
||||
PRIMARY KEY(id),
|
||||
FOREIGN KEY(id_user) REFERENCES users(id) ON DELETE CASCADE
|
||||
);
|
||||
/* hash = hash(pack_hash, !key_pasw) */
|
||||
/* spubl = encrypt[!key_pasw](public_key) */
|
||||
/* sname = encrypt[!key_pasw](nickname) */
|
||||
/* head = encrypt[!key_pasw](title) */
|
||||
/* body = encrypt[!key_pasw](message) */
|
||||
/* addtime = encrypt[!key_pasw](time_rec) */
|
||||
CREATE TABLE IF NOT EXISTS emails (
|
||||
id INTEGER,
|
||||
id_user INTEGER,
|
||||
deleted BOOLEAN DEFAULT 0,
|
||||
hash VARCHAR(255) UNIQUE,
|
||||
spubl TEXT,
|
||||
sname NVARCHAR(255),
|
||||
head NVARCHAR(255),
|
||||
body TEXT,
|
||||
addtime TEXT,
|
||||
PRIMARY KEY(id),
|
||||
FOREIGN KEY(id_user) REFERENCES users(id) ON DELETE CASCADE
|
||||
);
|
||||
```
|
||||
|
||||
### Email page
|
||||
<img src="/userside/images/HES8.png" alt="EmailPage"/>
|
||||
|
||||
1022
cdatabase.go
1022
cdatabase.go
File diff suppressed because it is too large
Load Diff
70
cmodels.go
70
cmodels.go
@ -1,35 +1,35 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"crypto/rsa"
|
||||
"database/sql"
|
||||
_ "github.com/mattn/go-sqlite3"
|
||||
"sync"
|
||||
)
|
||||
|
||||
type DB struct {
|
||||
ptr *sql.DB
|
||||
mtx sync.Mutex
|
||||
}
|
||||
|
||||
type Sessions struct {
|
||||
mpn map[string]*sessionData
|
||||
mtx sync.Mutex
|
||||
}
|
||||
|
||||
type User struct {
|
||||
Id int
|
||||
Name string
|
||||
Pasw []byte
|
||||
Priv *rsa.PrivateKey
|
||||
}
|
||||
|
||||
type Email struct {
|
||||
Id int
|
||||
SenderName string
|
||||
SenderPubl string
|
||||
Head string
|
||||
Body string
|
||||
Hash string
|
||||
Time string
|
||||
}
|
||||
package main
|
||||
|
||||
import (
|
||||
"crypto/rsa"
|
||||
"database/sql"
|
||||
_ "github.com/mattn/go-sqlite3"
|
||||
"sync"
|
||||
)
|
||||
|
||||
type DB struct {
|
||||
ptr *sql.DB
|
||||
mtx sync.Mutex
|
||||
}
|
||||
|
||||
type Sessions struct {
|
||||
mpn map[string]*sessionData
|
||||
mtx sync.Mutex
|
||||
}
|
||||
|
||||
type User struct {
|
||||
Id int
|
||||
Name string
|
||||
Pasw []byte
|
||||
Priv *rsa.PrivateKey
|
||||
}
|
||||
|
||||
type Email struct {
|
||||
Id int
|
||||
SenderName string
|
||||
SenderPubl string
|
||||
Head string
|
||||
Body string
|
||||
Hash string
|
||||
Time string
|
||||
}
|
||||
|
||||
47
compile.c
Normal file
47
compile.c
Normal file
@ -0,0 +1,47 @@
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
int main(void) {
|
||||
const char *compiler = "go build";
|
||||
const char *filenames[] = {"client", "server"};
|
||||
const char *platforms[] = {"windows", "linux"};
|
||||
const char *archs[] = {"amd64", "386", "arm"};
|
||||
const char *files[] = {
|
||||
"client.go cdatabase.go cmodels.go csessions.go gconsts.go",
|
||||
"server.go sconfig.go sdatabase.go gconsts.go"
|
||||
};
|
||||
|
||||
char command[BUFSIZ];
|
||||
char retfile[BUFSIZ];
|
||||
|
||||
for (int k = 0; k < sizeof(filenames)/sizeof(filenames[0]); ++k) {
|
||||
for (int i = 0; i < sizeof(platforms)/sizeof(platforms[0]); ++i) {
|
||||
#ifdef _WIN32
|
||||
snprintf(command, BUFSIZ, "set GOOS=%s", platforms[i]);
|
||||
printf("%s\n", command);
|
||||
system(command);
|
||||
#endif
|
||||
for (int j = 0; j < sizeof(archs)/sizeof(archs[0]); ++j) {
|
||||
#ifdef _WIN32
|
||||
snprintf(command, BUFSIZ, "set GOARCH=%s", archs[j]);
|
||||
printf("%s\n", command);
|
||||
system(command);
|
||||
#endif
|
||||
snprintf(retfile, BUFSIZ, "%s_%s_%s", filenames[k], platforms[i], archs[j]);
|
||||
if (strcmp(platforms[i], "windows") == 0) {
|
||||
strcat(retfile, ".exe");
|
||||
}
|
||||
#ifdef _WIN32
|
||||
snprintf(command, BUFSIZ, "%s -o %s %s", compiler, retfile, files[k]);
|
||||
#else
|
||||
snprintf(command, BUFSIZ, "GOOS=%s GOARCH=%s %s -o %s %s", platforms[i], archs[j], compiler, retfile, files[k]);
|
||||
#endif
|
||||
printf("%s\n", command);
|
||||
system(command);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
180
csessions.go
180
csessions.go
@ -1,90 +1,90 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
gp "github.com/number571/gopeer"
|
||||
"net/http"
|
||||
"time"
|
||||
)
|
||||
|
||||
type sessionData struct {
|
||||
user *User
|
||||
ts time.Time
|
||||
}
|
||||
|
||||
func NewSessions() *Sessions {
|
||||
return &Sessions{
|
||||
mpn: make(map[string]*sessionData),
|
||||
}
|
||||
}
|
||||
|
||||
func (sessions *Sessions) Set(w http.ResponseWriter, user *User) {
|
||||
sessions.mtx.Lock()
|
||||
defer sessions.mtx.Unlock()
|
||||
for k, v := range sessions.mpn {
|
||||
if v.user.Name == user.Name {
|
||||
delete(sessions.mpn, k)
|
||||
break
|
||||
}
|
||||
}
|
||||
key := gp.Base64Encode(gp.GenerateBytes(32))
|
||||
sessions.mpn[key] = &sessionData{
|
||||
user: user,
|
||||
ts: time.Now(),
|
||||
}
|
||||
createCookie(w, key)
|
||||
}
|
||||
|
||||
func (sessions *Sessions) Get(r *http.Request) *User {
|
||||
sessions.mtx.Lock()
|
||||
defer sessions.mtx.Unlock()
|
||||
key := readCookie(r)
|
||||
if _, ok := sessions.mpn[key]; !ok {
|
||||
return nil
|
||||
}
|
||||
sessions.mpn[key].ts = time.Now()
|
||||
return sessions.mpn[key].user
|
||||
}
|
||||
|
||||
func (sessions *Sessions) Del(w http.ResponseWriter, r *http.Request) {
|
||||
sessions.mtx.Lock()
|
||||
defer sessions.mtx.Unlock()
|
||||
delete(sessions.mpn, readCookie(r))
|
||||
deleteCookie(w)
|
||||
}
|
||||
|
||||
func (sessions *Sessions) DelByTime(t time.Duration) {
|
||||
sessions.mtx.Lock()
|
||||
defer sessions.mtx.Unlock()
|
||||
currTime := time.Now()
|
||||
for k, v := range sessions.mpn {
|
||||
if v.ts.Add(t).Before(currTime) {
|
||||
delete(sessions.mpn, k)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func createCookie(w http.ResponseWriter, data string) {
|
||||
c := http.Cookie{
|
||||
Name: "storage",
|
||||
Value: data,
|
||||
MaxAge: 3600,
|
||||
}
|
||||
http.SetCookie(w, &c)
|
||||
}
|
||||
|
||||
func readCookie(r *http.Request) string {
|
||||
c, err := r.Cookie("storage")
|
||||
value := ""
|
||||
if err == nil {
|
||||
value = c.Value
|
||||
}
|
||||
return value
|
||||
}
|
||||
|
||||
func deleteCookie(w http.ResponseWriter) {
|
||||
c := http.Cookie{
|
||||
Name: "storage",
|
||||
MaxAge: -1,
|
||||
}
|
||||
http.SetCookie(w, &c)
|
||||
}
|
||||
package main
|
||||
|
||||
import (
|
||||
gp "github.com/number571/gopeer"
|
||||
"net/http"
|
||||
"time"
|
||||
)
|
||||
|
||||
type sessionData struct {
|
||||
user *User
|
||||
ts time.Time
|
||||
}
|
||||
|
||||
func NewSessions() *Sessions {
|
||||
return &Sessions{
|
||||
mpn: make(map[string]*sessionData),
|
||||
}
|
||||
}
|
||||
|
||||
func (sessions *Sessions) Set(w http.ResponseWriter, user *User) {
|
||||
sessions.mtx.Lock()
|
||||
defer sessions.mtx.Unlock()
|
||||
for k, v := range sessions.mpn {
|
||||
if v.user.Name == user.Name {
|
||||
delete(sessions.mpn, k)
|
||||
break
|
||||
}
|
||||
}
|
||||
key := gp.Base64Encode(gp.GenerateBytes(32))
|
||||
sessions.mpn[key] = &sessionData{
|
||||
user: user,
|
||||
ts: time.Now(),
|
||||
}
|
||||
createCookie(w, key)
|
||||
}
|
||||
|
||||
func (sessions *Sessions) Get(r *http.Request) *User {
|
||||
sessions.mtx.Lock()
|
||||
defer sessions.mtx.Unlock()
|
||||
key := readCookie(r)
|
||||
if _, ok := sessions.mpn[key]; !ok {
|
||||
return nil
|
||||
}
|
||||
sessions.mpn[key].ts = time.Now()
|
||||
return sessions.mpn[key].user
|
||||
}
|
||||
|
||||
func (sessions *Sessions) Del(w http.ResponseWriter, r *http.Request) {
|
||||
sessions.mtx.Lock()
|
||||
defer sessions.mtx.Unlock()
|
||||
delete(sessions.mpn, readCookie(r))
|
||||
deleteCookie(w)
|
||||
}
|
||||
|
||||
func (sessions *Sessions) DelByTime(t time.Duration) {
|
||||
sessions.mtx.Lock()
|
||||
defer sessions.mtx.Unlock()
|
||||
currTime := time.Now()
|
||||
for k, v := range sessions.mpn {
|
||||
if v.ts.Add(t).Before(currTime) {
|
||||
delete(sessions.mpn, k)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func createCookie(w http.ResponseWriter, data string) {
|
||||
c := http.Cookie{
|
||||
Name: "storage",
|
||||
Value: data,
|
||||
MaxAge: 3600,
|
||||
}
|
||||
http.SetCookie(w, &c)
|
||||
}
|
||||
|
||||
func readCookie(r *http.Request) string {
|
||||
c, err := r.Cookie("storage")
|
||||
value := ""
|
||||
if err == nil {
|
||||
value = c.Value
|
||||
}
|
||||
return value
|
||||
}
|
||||
|
||||
func deleteCookie(w http.ResponseWriter) {
|
||||
c := http.Cookie{
|
||||
Name: "storage",
|
||||
MaxAge: -1,
|
||||
}
|
||||
http.SetCookie(w, &c)
|
||||
}
|
||||
|
||||
120
gconsts.go
120
gconsts.go
@ -1,60 +1,60 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"flag"
|
||||
gp "github.com/number571/gopeer"
|
||||
"golang.org/x/net/proxy"
|
||||
"net/http"
|
||||
"encoding/json"
|
||||
"net/url"
|
||||
"time"
|
||||
)
|
||||
|
||||
const (
|
||||
TMESSAGE = "\005\007\001\000\001\007\005"
|
||||
)
|
||||
|
||||
var (
|
||||
MAXESIZE = uint(0)
|
||||
POWSDIFF = uint(0)
|
||||
OPENADDR = ""
|
||||
HTCLIENT = new(http.Client)
|
||||
)
|
||||
|
||||
func hesDefaultInit(address string) {
|
||||
socks5Ptr := flag.String("socks5", "", "enable socks5 and create proxy connection")
|
||||
addrPtr := flag.String("open", address, "open address for hidden email server")
|
||||
flag.Parse()
|
||||
OPENADDR = *addrPtr
|
||||
if *socks5Ptr != "" {
|
||||
socks5, err := url.Parse("socks5://" + *socks5Ptr)
|
||||
if err != nil {
|
||||
panic("error: socks5 conn")
|
||||
}
|
||||
dialer, err := proxy.FromURL(socks5, proxy.Direct)
|
||||
if err != nil {
|
||||
panic("error: dialer")
|
||||
}
|
||||
HTCLIENT = &http.Client{
|
||||
Transport: &http.Transport{Dial: dialer.Dial},
|
||||
Timeout: time.Second * 15,
|
||||
}
|
||||
}
|
||||
gp.Set(gp.SettingsType{
|
||||
"POWS_DIFF": uint(25),
|
||||
"PACK_SIZE": uint(8 << 20),
|
||||
"AKEY_SIZE": uint(2 << 10),
|
||||
"SKEY_SIZE": uint(1 << 5),
|
||||
"RAND_SIZE": uint(1 << 4),
|
||||
})
|
||||
MAXESIZE = gp.Get("PACK_SIZE").(uint)
|
||||
POWSDIFF = gp.Get("POWS_DIFF").(uint)
|
||||
}
|
||||
|
||||
func serialize(data interface{}) []byte {
|
||||
res, err := json.MarshalIndent(data, "", "\t")
|
||||
if err != nil {
|
||||
return nil
|
||||
}
|
||||
return res
|
||||
}
|
||||
package main
|
||||
|
||||
import (
|
||||
"flag"
|
||||
gp "github.com/number571/gopeer"
|
||||
"golang.org/x/net/proxy"
|
||||
"net/http"
|
||||
"encoding/json"
|
||||
"net/url"
|
||||
"time"
|
||||
)
|
||||
|
||||
const (
|
||||
TMESSAGE = "\005\007\001\000\001\007\005"
|
||||
)
|
||||
|
||||
var (
|
||||
MAXESIZE = uint(0)
|
||||
POWSDIFF = uint(0)
|
||||
OPENADDR = ""
|
||||
HTCLIENT = new(http.Client)
|
||||
)
|
||||
|
||||
func hesDefaultInit(address string) {
|
||||
socks5Ptr := flag.String("socks5", "", "enable socks5 and create proxy connection")
|
||||
addrPtr := flag.String("open", address, "open address for hidden email server")
|
||||
flag.Parse()
|
||||
OPENADDR = *addrPtr
|
||||
if *socks5Ptr != "" {
|
||||
socks5, err := url.Parse("socks5://" + *socks5Ptr)
|
||||
if err != nil {
|
||||
panic("error: socks5 conn")
|
||||
}
|
||||
dialer, err := proxy.FromURL(socks5, proxy.Direct)
|
||||
if err != nil {
|
||||
panic("error: dialer")
|
||||
}
|
||||
HTCLIENT = &http.Client{
|
||||
Transport: &http.Transport{Dial: dialer.Dial},
|
||||
Timeout: time.Second * 15,
|
||||
}
|
||||
}
|
||||
gp.Set(gp.SettingsType{
|
||||
"POWS_DIFF": uint(25),
|
||||
"PACK_SIZE": uint(8 << 20),
|
||||
"AKEY_SIZE": uint(2 << 10),
|
||||
"SKEY_SIZE": uint(1 << 5),
|
||||
"RAND_SIZE": uint(1 << 4),
|
||||
})
|
||||
MAXESIZE = gp.Get("PACK_SIZE").(uint)
|
||||
POWSDIFF = gp.Get("POWS_DIFF").(uint)
|
||||
}
|
||||
|
||||
func serialize(data interface{}) []byte {
|
||||
res, err := json.MarshalIndent(data, "", "\t")
|
||||
if err != nil {
|
||||
return nil
|
||||
}
|
||||
return res
|
||||
}
|
||||
|
||||
20
go.mod
20
go.mod
@ -1,10 +1,10 @@
|
||||
module github.com/number571/hes
|
||||
|
||||
go 1.16
|
||||
|
||||
require (
|
||||
github.com/boombuler/barcode v1.0.1
|
||||
github.com/mattn/go-sqlite3 v1.14.7
|
||||
github.com/number571/gopeer v1.2.10-0.20210519010712-06d626fa7dee
|
||||
golang.org/x/net v0.0.0-20210510120150-4163338589ed
|
||||
)
|
||||
module github.com/number571/hes
|
||||
|
||||
go 1.16
|
||||
|
||||
require (
|
||||
github.com/boombuler/barcode v1.0.1
|
||||
github.com/mattn/go-sqlite3 v1.14.7
|
||||
github.com/number571/gopeer v1.2.10-0.20210519010712-06d626fa7dee
|
||||
golang.org/x/net v0.0.0-20210510120150-4163338589ed
|
||||
)
|
||||
|
||||
26
go.sum
26
go.sum
@ -1,13 +1,13 @@
|
||||
github.com/boombuler/barcode v1.0.1 h1:NDBbPmhS+EqABEs5Kg3n/5ZNjy73Pz7SIV+KCeqyXcs=
|
||||
github.com/boombuler/barcode v1.0.1/go.mod h1:paBWMcWSl3LHKBqUq+rly7CNSldXjb2rDl3JlRe0mD8=
|
||||
github.com/mattn/go-sqlite3 v1.14.7 h1:fxWBnXkxfM6sRiuH3bqJ4CfzZojMOLVc0UTsTglEghA=
|
||||
github.com/mattn/go-sqlite3 v1.14.7/go.mod h1:NyWgC/yNuGj7Q9rpYnZvas74GogHl5/Z4A/KQRfk6bU=
|
||||
github.com/number571/gopeer v1.2.10-0.20210519010712-06d626fa7dee h1:GGp+jaOFZNObKXxe69T6055P/42aYb9pAXbo0oHlpow=
|
||||
github.com/number571/gopeer v1.2.10-0.20210519010712-06d626fa7dee/go.mod h1:clJDji1rWG99DesfWt1CQTUh0Yp4prmZnJv8e18unEk=
|
||||
golang.org/x/net v0.0.0-20210510120150-4163338589ed h1:p9UgmWI9wKpfYmgaV/IZKGdXc5qEK45tDwwwDyjS26I=
|
||||
golang.org/x/net v0.0.0-20210510120150-4163338589ed/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
|
||||
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
|
||||
golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||
github.com/boombuler/barcode v1.0.1 h1:NDBbPmhS+EqABEs5Kg3n/5ZNjy73Pz7SIV+KCeqyXcs=
|
||||
github.com/boombuler/barcode v1.0.1/go.mod h1:paBWMcWSl3LHKBqUq+rly7CNSldXjb2rDl3JlRe0mD8=
|
||||
github.com/mattn/go-sqlite3 v1.14.7 h1:fxWBnXkxfM6sRiuH3bqJ4CfzZojMOLVc0UTsTglEghA=
|
||||
github.com/mattn/go-sqlite3 v1.14.7/go.mod h1:NyWgC/yNuGj7Q9rpYnZvas74GogHl5/Z4A/KQRfk6bU=
|
||||
github.com/number571/gopeer v1.2.10-0.20210519010712-06d626fa7dee h1:GGp+jaOFZNObKXxe69T6055P/42aYb9pAXbo0oHlpow=
|
||||
github.com/number571/gopeer v1.2.10-0.20210519010712-06d626fa7dee/go.mod h1:clJDji1rWG99DesfWt1CQTUh0Yp4prmZnJv8e18unEk=
|
||||
golang.org/x/net v0.0.0-20210510120150-4163338589ed h1:p9UgmWI9wKpfYmgaV/IZKGdXc5qEK45tDwwwDyjS26I=
|
||||
golang.org/x/net v0.0.0-20210510120150-4163338589ed/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
|
||||
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
|
||||
golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||
|
||||
84
sconfig.go
84
sconfig.go
@ -1,42 +1,42 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
)
|
||||
|
||||
type CFG struct {
|
||||
Pasw string `json:"pasw"`
|
||||
Conns [][2]string `json:"conns"`
|
||||
}
|
||||
|
||||
func NewCFG(filename string) *CFG {
|
||||
var config = new(CFG)
|
||||
config.Conns = append(config.Conns, [2]string{
|
||||
"addr",
|
||||
"pasw",
|
||||
})
|
||||
if !fileIsExist(filename) {
|
||||
err := ioutil.WriteFile(filename, serialize(config), 0644)
|
||||
if err != nil {
|
||||
return nil
|
||||
}
|
||||
}
|
||||
content, err := ioutil.ReadFile(filename)
|
||||
if err != nil {
|
||||
return nil
|
||||
}
|
||||
err = json.Unmarshal(content, config)
|
||||
if err != nil {
|
||||
return nil
|
||||
}
|
||||
return config
|
||||
}
|
||||
|
||||
func fileIsExist(filename string) bool {
|
||||
if _, err := os.Stat(filename); os.IsNotExist(err) {
|
||||
return false
|
||||
}
|
||||
return true
|
||||
}
|
||||
package main
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
)
|
||||
|
||||
type CFG struct {
|
||||
Pasw string `json:"pasw"`
|
||||
Conns [][2]string `json:"conns"`
|
||||
}
|
||||
|
||||
func NewCFG(filename string) *CFG {
|
||||
var config = new(CFG)
|
||||
config.Conns = append(config.Conns, [2]string{
|
||||
"addr",
|
||||
"pasw",
|
||||
})
|
||||
if !fileIsExist(filename) {
|
||||
err := ioutil.WriteFile(filename, serialize(config), 0644)
|
||||
if err != nil {
|
||||
return nil
|
||||
}
|
||||
}
|
||||
content, err := ioutil.ReadFile(filename)
|
||||
if err != nil {
|
||||
return nil
|
||||
}
|
||||
err = json.Unmarshal(content, config)
|
||||
if err != nil {
|
||||
return nil
|
||||
}
|
||||
return config
|
||||
}
|
||||
|
||||
func fileIsExist(filename string) bool {
|
||||
if _, err := os.Stat(filename); os.IsNotExist(err) {
|
||||
return false
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
170
sdatabase.go
170
sdatabase.go
@ -1,85 +1,85 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"database/sql"
|
||||
_ "github.com/mattn/go-sqlite3"
|
||||
gp "github.com/number571/gopeer"
|
||||
"sync"
|
||||
"time"
|
||||
)
|
||||
|
||||
type DB struct {
|
||||
ptr *sql.DB
|
||||
mtx sync.Mutex
|
||||
}
|
||||
|
||||
func NewDB(filename string) *DB {
|
||||
db, err := sql.Open("sqlite3", filename)
|
||||
if err != nil {
|
||||
return nil
|
||||
}
|
||||
_, err = db.Exec(`
|
||||
PRAGMA secure_delete=ON;
|
||||
CREATE TABLE IF NOT EXISTS emails (
|
||||
id INTEGER,
|
||||
recv VARCHAR(255),
|
||||
hash VARCHAR(255) UNIQUE,
|
||||
data TEXT,
|
||||
addtime DATETIME DEFAULT CURRENT_TIMESTAMP,
|
||||
PRIMARY KEY(id)
|
||||
);
|
||||
`)
|
||||
if err != nil {
|
||||
return nil
|
||||
}
|
||||
return &DB{
|
||||
ptr: db,
|
||||
}
|
||||
}
|
||||
|
||||
func (db *DB) SetEmail(recv string, pack *gp.Package) error {
|
||||
db.mtx.Lock()
|
||||
defer db.mtx.Unlock()
|
||||
_, err := db.ptr.Exec(
|
||||
"INSERT INTO emails (recv, hash, data) VALUES ($1, $2, $3)",
|
||||
recv,
|
||||
gp.Base64Encode(pack.Body.Hash),
|
||||
string(gp.SerializePackage(pack)),
|
||||
)
|
||||
return err
|
||||
}
|
||||
|
||||
func (db *DB) GetEmail(id int, recv string) string {
|
||||
db.mtx.Lock()
|
||||
defer db.mtx.Unlock()
|
||||
var data string
|
||||
row := db.ptr.QueryRow(
|
||||
"SELECT data FROM emails WHERE recv=$1 ORDER BY id LIMIT 1 OFFSET $2",
|
||||
recv,
|
||||
id-1,
|
||||
)
|
||||
row.Scan(&data)
|
||||
return data
|
||||
}
|
||||
|
||||
func (db *DB) DelEmailsByTime(t time.Duration) error {
|
||||
db.mtx.Lock()
|
||||
defer db.mtx.Unlock()
|
||||
_, err := db.ptr.Exec(
|
||||
"DELETE FROM emails WHERE addtime < datetime('now', '-' || $1 || ' seconds')",
|
||||
uint64(t)/1000000000, // seconds
|
||||
)
|
||||
return err
|
||||
}
|
||||
|
||||
func (db *DB) Size(recv string) int {
|
||||
db.mtx.Lock()
|
||||
defer db.mtx.Unlock()
|
||||
var data int
|
||||
row := db.ptr.QueryRow(
|
||||
"SELECT COUNT(*) FROM emails WHERE recv=$1",
|
||||
recv,
|
||||
)
|
||||
row.Scan(&data)
|
||||
return data
|
||||
}
|
||||
package main
|
||||
|
||||
import (
|
||||
"database/sql"
|
||||
_ "github.com/mattn/go-sqlite3"
|
||||
gp "github.com/number571/gopeer"
|
||||
"sync"
|
||||
"time"
|
||||
)
|
||||
|
||||
type DB struct {
|
||||
ptr *sql.DB
|
||||
mtx sync.Mutex
|
||||
}
|
||||
|
||||
func NewDB(filename string) *DB {
|
||||
db, err := sql.Open("sqlite3", filename)
|
||||
if err != nil {
|
||||
return nil
|
||||
}
|
||||
_, err = db.Exec(`
|
||||
PRAGMA secure_delete=ON;
|
||||
CREATE TABLE IF NOT EXISTS emails (
|
||||
id INTEGER,
|
||||
recv VARCHAR(255),
|
||||
hash VARCHAR(255) UNIQUE,
|
||||
data TEXT,
|
||||
addtime DATETIME DEFAULT CURRENT_TIMESTAMP,
|
||||
PRIMARY KEY(id)
|
||||
);
|
||||
`)
|
||||
if err != nil {
|
||||
return nil
|
||||
}
|
||||
return &DB{
|
||||
ptr: db,
|
||||
}
|
||||
}
|
||||
|
||||
func (db *DB) SetEmail(recv string, pack *gp.Package) error {
|
||||
db.mtx.Lock()
|
||||
defer db.mtx.Unlock()
|
||||
_, err := db.ptr.Exec(
|
||||
"INSERT INTO emails (recv, hash, data) VALUES ($1, $2, $3)",
|
||||
recv,
|
||||
gp.Base64Encode(pack.Body.Hash),
|
||||
string(gp.SerializePackage(pack)),
|
||||
)
|
||||
return err
|
||||
}
|
||||
|
||||
func (db *DB) GetEmail(id int, recv string) string {
|
||||
db.mtx.Lock()
|
||||
defer db.mtx.Unlock()
|
||||
var data string
|
||||
row := db.ptr.QueryRow(
|
||||
"SELECT data FROM emails WHERE recv=$1 ORDER BY id LIMIT 1 OFFSET $2",
|
||||
recv,
|
||||
id-1,
|
||||
)
|
||||
row.Scan(&data)
|
||||
return data
|
||||
}
|
||||
|
||||
func (db *DB) DelEmailsByTime(t time.Duration) error {
|
||||
db.mtx.Lock()
|
||||
defer db.mtx.Unlock()
|
||||
_, err := db.ptr.Exec(
|
||||
"DELETE FROM emails WHERE addtime < datetime('now', '-' || $1 || ' seconds')",
|
||||
uint64(t)/1000000000, // seconds
|
||||
)
|
||||
return err
|
||||
}
|
||||
|
||||
func (db *DB) Size(recv string) int {
|
||||
db.mtx.Lock()
|
||||
defer db.mtx.Unlock()
|
||||
var data int
|
||||
row := db.ptr.QueryRow(
|
||||
"SELECT COUNT(*) FROM emails WHERE recv=$1",
|
||||
recv,
|
||||
)
|
||||
row.Scan(&data)
|
||||
return data
|
||||
}
|
||||
|
||||
16
server.cfg
16
server.cfg
@ -1,9 +1,9 @@
|
||||
{
|
||||
"pasw": "",
|
||||
"conns": [
|
||||
[
|
||||
"addr",
|
||||
"pasw"
|
||||
]
|
||||
]
|
||||
{
|
||||
"pasw": "",
|
||||
"conns": [
|
||||
[
|
||||
"addr",
|
||||
"pasw"
|
||||
]
|
||||
]
|
||||
}
|
||||
342
server.go
342
server.go
@ -1,171 +1,171 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
gp "github.com/number571/gopeer"
|
||||
"net/http"
|
||||
"time"
|
||||
)
|
||||
|
||||
var (
|
||||
DATABASE = NewDB("server.db")
|
||||
FLCONFIG = NewCFG("server.cfg")
|
||||
)
|
||||
|
||||
func init() {
|
||||
go delOldEmailsByTime(24*time.Hour, 6*time.Hour)
|
||||
hesDefaultInit("localhost:8080")
|
||||
fmt.Println("Server is listening...\n")
|
||||
}
|
||||
|
||||
func delOldEmailsByTime(deltime, period time.Duration) {
|
||||
for {
|
||||
DATABASE.DelEmailsByTime(deltime)
|
||||
time.Sleep(period)
|
||||
}
|
||||
}
|
||||
|
||||
func main() {
|
||||
http.HandleFunc("/", indexPage)
|
||||
http.HandleFunc("/email/send", emailSendPage)
|
||||
http.HandleFunc("/email/recv", emailRecvPage)
|
||||
http.ListenAndServe(OPENADDR, nil)
|
||||
}
|
||||
|
||||
func help() string {
|
||||
return `
|
||||
1. exit - close server;
|
||||
2. help - commands info;
|
||||
3. list - list connections;
|
||||
4. append - append connect to list;
|
||||
5. delete - delete connect from list;
|
||||
`
|
||||
}
|
||||
|
||||
func indexPage(w http.ResponseWriter, r *http.Request) {
|
||||
var req struct {
|
||||
Macp string `json:"macp"`
|
||||
}
|
||||
if r.Method != "POST" {
|
||||
response(w, 0, "hidden email service")
|
||||
return
|
||||
}
|
||||
if r.ContentLength > int64(MAXESIZE) {
|
||||
response(w, 1, "error: max size")
|
||||
return
|
||||
}
|
||||
err := json.NewDecoder(r.Body).Decode(&req)
|
||||
if err != nil {
|
||||
response(w, 2, "error: parse json")
|
||||
return
|
||||
}
|
||||
pasw := gp.HashSum([]byte(FLCONFIG.Pasw))
|
||||
dect := gp.DecryptAES(pasw, gp.Base64Decode(req.Macp))
|
||||
if !bytes.Equal([]byte(TMESSAGE), dect) {
|
||||
response(w, 3, "error: message authentication code")
|
||||
return
|
||||
}
|
||||
response(w, 0, "success: check connection")
|
||||
}
|
||||
|
||||
func emailSendPage(w http.ResponseWriter, r *http.Request) {
|
||||
var req struct {
|
||||
Recv string `json:"recv"`
|
||||
Data string `json:"data"`
|
||||
Macp string `json:"macp"`
|
||||
}
|
||||
if r.Method != "POST" {
|
||||
response(w, 1, "error: method != POST")
|
||||
return
|
||||
}
|
||||
if r.ContentLength > int64(MAXESIZE) {
|
||||
response(w, 2, "error: max size")
|
||||
return
|
||||
}
|
||||
err := json.NewDecoder(r.Body).Decode(&req)
|
||||
if err != nil {
|
||||
response(w, 3, "error: parse json")
|
||||
return
|
||||
}
|
||||
pack := gp.DeserializePackage([]byte(req.Data))
|
||||
if pack == nil {
|
||||
response(w, 4, "error: deserialize package")
|
||||
return
|
||||
}
|
||||
hash := pack.Body.Hash
|
||||
if !gp.ProofIsValid(hash, POWSDIFF, pack.Body.Npow) {
|
||||
response(w, 5, "error: proof of work")
|
||||
return
|
||||
}
|
||||
pasw := gp.HashSum([]byte(FLCONFIG.Pasw))
|
||||
dech := gp.DecryptAES(pasw, gp.Base64Decode(req.Macp))
|
||||
if !bytes.Equal(hash, dech) {
|
||||
response(w, 6, "error: message authentication code")
|
||||
return
|
||||
}
|
||||
err = DATABASE.SetEmail(req.Recv, pack)
|
||||
if err != nil {
|
||||
response(w, 7, "error: save email")
|
||||
return
|
||||
}
|
||||
for _, conn := range FLCONFIG.Conns {
|
||||
go func() {
|
||||
addr := conn[0]
|
||||
pasw := gp.HashSum([]byte(conn[1]))
|
||||
req.Macp = gp.Base64Encode(gp.EncryptAES(pasw, hash))
|
||||
resp, err := HTCLIENT.Post(
|
||||
"http://"+addr+"/email/send",
|
||||
"application/json",
|
||||
bytes.NewReader(serialize(req)),
|
||||
)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
resp.Body.Close()
|
||||
}()
|
||||
}
|
||||
response(w, 0, "success: email saved")
|
||||
}
|
||||
|
||||
func emailRecvPage(w http.ResponseWriter, r *http.Request) {
|
||||
var req struct {
|
||||
Recv string `json:"recv"`
|
||||
Data int `json:"data"`
|
||||
}
|
||||
if r.Method != "POST" {
|
||||
response(w, 1, "error: method != POST")
|
||||
return
|
||||
}
|
||||
if r.ContentLength > int64(MAXESIZE) {
|
||||
response(w, 2, "error: max size")
|
||||
return
|
||||
}
|
||||
err := json.NewDecoder(r.Body).Decode(&req)
|
||||
if err != nil {
|
||||
response(w, 3, "error: parse json")
|
||||
return
|
||||
}
|
||||
if req.Data == 0 {
|
||||
response(w, 0, fmt.Sprintf("%d", DATABASE.Size(req.Recv)))
|
||||
return
|
||||
}
|
||||
res := DATABASE.GetEmail(req.Data, req.Recv)
|
||||
if res == "" {
|
||||
response(w, 4, "error: nothing data")
|
||||
return
|
||||
}
|
||||
response(w, 0, res)
|
||||
}
|
||||
|
||||
func response(w http.ResponseWriter, ret int, res string) {
|
||||
w.Header().Set("Content-Type", "application/json")
|
||||
var resp struct {
|
||||
Result string `json:"result"`
|
||||
Return int `json:"return"`
|
||||
}
|
||||
resp.Result = res
|
||||
resp.Return = ret
|
||||
json.NewEncoder(w).Encode(resp)
|
||||
}
|
||||
package main
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
gp "github.com/number571/gopeer"
|
||||
"net/http"
|
||||
"time"
|
||||
)
|
||||
|
||||
var (
|
||||
DATABASE = NewDB("server.db")
|
||||
FLCONFIG = NewCFG("server.cfg")
|
||||
)
|
||||
|
||||
func init() {
|
||||
go delOldEmailsByTime(24*time.Hour, 6*time.Hour)
|
||||
hesDefaultInit("localhost:8080")
|
||||
fmt.Printf("Server is listening [%s] ...\n\n", OPENADDR)
|
||||
}
|
||||
|
||||
func delOldEmailsByTime(deltime, period time.Duration) {
|
||||
for {
|
||||
DATABASE.DelEmailsByTime(deltime)
|
||||
time.Sleep(period)
|
||||
}
|
||||
}
|
||||
|
||||
func main() {
|
||||
http.HandleFunc("/", indexPage)
|
||||
http.HandleFunc("/email/send", emailSendPage)
|
||||
http.HandleFunc("/email/recv", emailRecvPage)
|
||||
http.ListenAndServe(OPENADDR, nil)
|
||||
}
|
||||
|
||||
func help() string {
|
||||
return `
|
||||
1. exit - close server;
|
||||
2. help - commands info;
|
||||
3. list - list connections;
|
||||
4. append - append connect to list;
|
||||
5. delete - delete connect from list;
|
||||
`
|
||||
}
|
||||
|
||||
func indexPage(w http.ResponseWriter, r *http.Request) {
|
||||
var req struct {
|
||||
Macp string `json:"macp"`
|
||||
}
|
||||
if r.Method != "POST" {
|
||||
response(w, 0, "hidden email service")
|
||||
return
|
||||
}
|
||||
if r.ContentLength > int64(MAXESIZE) {
|
||||
response(w, 1, "error: max size")
|
||||
return
|
||||
}
|
||||
err := json.NewDecoder(r.Body).Decode(&req)
|
||||
if err != nil {
|
||||
response(w, 2, "error: parse json")
|
||||
return
|
||||
}
|
||||
pasw := gp.HashSum([]byte(FLCONFIG.Pasw))
|
||||
dect := gp.DecryptAES(pasw, gp.Base64Decode(req.Macp))
|
||||
if !bytes.Equal([]byte(TMESSAGE), dect) {
|
||||
response(w, 3, "error: message authentication code")
|
||||
return
|
||||
}
|
||||
response(w, 0, "success: check connection")
|
||||
}
|
||||
|
||||
func emailSendPage(w http.ResponseWriter, r *http.Request) {
|
||||
var req struct {
|
||||
Recv string `json:"recv"`
|
||||
Data string `json:"data"`
|
||||
Macp string `json:"macp"`
|
||||
}
|
||||
if r.Method != "POST" {
|
||||
response(w, 1, "error: method != POST")
|
||||
return
|
||||
}
|
||||
if r.ContentLength > int64(MAXESIZE) {
|
||||
response(w, 2, "error: max size")
|
||||
return
|
||||
}
|
||||
err := json.NewDecoder(r.Body).Decode(&req)
|
||||
if err != nil {
|
||||
response(w, 3, "error: parse json")
|
||||
return
|
||||
}
|
||||
pack := gp.DeserializePackage([]byte(req.Data))
|
||||
if pack == nil {
|
||||
response(w, 4, "error: deserialize package")
|
||||
return
|
||||
}
|
||||
hash := pack.Body.Hash
|
||||
if !gp.ProofIsValid(hash, POWSDIFF, pack.Body.Npow) {
|
||||
response(w, 5, "error: proof of work")
|
||||
return
|
||||
}
|
||||
pasw := gp.HashSum([]byte(FLCONFIG.Pasw))
|
||||
dech := gp.DecryptAES(pasw, gp.Base64Decode(req.Macp))
|
||||
if !bytes.Equal(hash, dech) {
|
||||
response(w, 6, "error: message authentication code")
|
||||
return
|
||||
}
|
||||
err = DATABASE.SetEmail(req.Recv, pack)
|
||||
if err != nil {
|
||||
response(w, 7, "error: save email")
|
||||
return
|
||||
}
|
||||
for _, conn := range FLCONFIG.Conns {
|
||||
go func() {
|
||||
addr := conn[0]
|
||||
pasw := gp.HashSum([]byte(conn[1]))
|
||||
req.Macp = gp.Base64Encode(gp.EncryptAES(pasw, hash))
|
||||
resp, err := HTCLIENT.Post(
|
||||
addr+"/email/send",
|
||||
"application/json",
|
||||
bytes.NewReader(serialize(req)),
|
||||
)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
resp.Body.Close()
|
||||
}()
|
||||
}
|
||||
response(w, 0, "success: email saved")
|
||||
}
|
||||
|
||||
func emailRecvPage(w http.ResponseWriter, r *http.Request) {
|
||||
var req struct {
|
||||
Recv string `json:"recv"`
|
||||
Data int `json:"data"`
|
||||
}
|
||||
if r.Method != "POST" {
|
||||
response(w, 1, "error: method != POST")
|
||||
return
|
||||
}
|
||||
if r.ContentLength > int64(MAXESIZE) {
|
||||
response(w, 2, "error: max size")
|
||||
return
|
||||
}
|
||||
err := json.NewDecoder(r.Body).Decode(&req)
|
||||
if err != nil {
|
||||
response(w, 3, "error: parse json")
|
||||
return
|
||||
}
|
||||
if req.Data == 0 {
|
||||
response(w, 0, fmt.Sprintf("%d", DATABASE.Size(req.Recv)))
|
||||
return
|
||||
}
|
||||
res := DATABASE.GetEmail(req.Data, req.Recv)
|
||||
if res == "" {
|
||||
response(w, 4, "error: nothing data")
|
||||
return
|
||||
}
|
||||
response(w, 0, res)
|
||||
}
|
||||
|
||||
func response(w http.ResponseWriter, ret int, res string) {
|
||||
w.Header().Set("Content-Type", "application/json")
|
||||
var resp struct {
|
||||
Result string `json:"result"`
|
||||
Return int `json:"return"`
|
||||
}
|
||||
resp.Result = res
|
||||
resp.Return = ret
|
||||
json.NewEncoder(w).Encode(resp)
|
||||
}
|
||||
|
||||
17948
userside/static/css/bootstrap.css
vendored
17948
userside/static/css/bootstrap.css
vendored
File diff suppressed because it is too large
Load Diff
7788
userside/static/js/bootstrap.js
vendored
7788
userside/static/js/bootstrap.js
vendored
File diff suppressed because it is too large
Load Diff
10
userside/static/js/jquery.js
vendored
10
userside/static/js/jquery.js
vendored
File diff suppressed because one or more lines are too long
@ -1,29 +1,29 @@
|
||||
function copy_text(id) {
|
||||
var copyText = document.getElementById(id);
|
||||
copyText.select();
|
||||
document.execCommand("copy");
|
||||
open_block('message_copy');
|
||||
}
|
||||
|
||||
function view_block(id) {
|
||||
var e = document.getElementById(id);
|
||||
if(e.style.display == 'block')
|
||||
e.style.display = 'none';
|
||||
else
|
||||
e.style.display = 'block';
|
||||
}
|
||||
|
||||
function open_block(id) {
|
||||
var e = document.getElementById(id);
|
||||
e.style.display = 'block';
|
||||
}
|
||||
|
||||
function close_block(id) {
|
||||
var e = document.getElementById(id);
|
||||
e.style.display = 'none';
|
||||
}
|
||||
|
||||
function clear_value(id) {
|
||||
var e = document.getElementById(id);
|
||||
e.value = "";
|
||||
}
|
||||
function copy_text(id) {
|
||||
var copyText = document.getElementById(id);
|
||||
copyText.select();
|
||||
document.execCommand("copy");
|
||||
open_block('message_copy');
|
||||
}
|
||||
|
||||
function view_block(id) {
|
||||
var e = document.getElementById(id);
|
||||
if(e.style.display == 'block')
|
||||
e.style.display = 'none';
|
||||
else
|
||||
e.style.display = 'block';
|
||||
}
|
||||
|
||||
function open_block(id) {
|
||||
var e = document.getElementById(id);
|
||||
e.style.display = 'block';
|
||||
}
|
||||
|
||||
function close_block(id) {
|
||||
var e = document.getElementById(id);
|
||||
e.style.display = 'none';
|
||||
}
|
||||
|
||||
function clear_value(id) {
|
||||
var e = document.getElementById(id);
|
||||
e.value = "";
|
||||
}
|
||||
|
||||
@ -1,83 +1,83 @@
|
||||
{{ define "title" }}
|
||||
Account
|
||||
{{ end }}
|
||||
|
||||
{{ define "main" }}
|
||||
<div id="message_copy" style="display: none" class="text-light mx-auto">
|
||||
<div class="alert alert-success" role="alert">
|
||||
<button type="button" class="close" onclick="close_block('message_copy')">
|
||||
<span>×</span>
|
||||
</button>
|
||||
Key copied
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group row">
|
||||
<div class="col-md-6 w-50">
|
||||
<button type="button" class="btn btn-secondary divtext w-100" disabled>{{ .Auth }}</button>
|
||||
</div>
|
||||
<div class="col-md-6 w-50">
|
||||
<button type="button" class="btn btn-danger w-100" onclick="view_block('input_password'); clear_value('username'); clear_value('password'); close_block('view_private_key'); close_block('view_public_key')">Delete account</button>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group row">
|
||||
<div class="col-md-6 w-50">
|
||||
<button type="button" class="btn btn-info w-100" onclick="view_block('view_public_key'); close_block('view_private_key'); close_block('input_password')">Public key</button>
|
||||
</div>
|
||||
<div class="col-md-6 w-50">
|
||||
<button type="button" class="btn btn-info w-100" onclick="view_block('view_private_key'); close_block('view_public_key'); close_block('input_password')">Private key</button>
|
||||
</div>
|
||||
</div>
|
||||
<div id="view_public_key" style="display: none" class="card text-white bg-dark mb-3">
|
||||
<h5 class="card-header">Public key</h5>
|
||||
<div class="card-header">
|
||||
<div class="form-group row">
|
||||
<div class="col-md-6 w-50">
|
||||
<button type="button" class="btn btn-success w-100" onclick="copy_text('public_key')">Copy</button>
|
||||
</div>
|
||||
<div class="col-md-6 w-50">
|
||||
<form class="text-center" method="POST" action="/account/public_key">
|
||||
<input type="submit" name="submit" value="QR code" class="btn btn-success w-100">
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<h6 class="card-text">{{ .PublicKey }}</h6>
|
||||
</div>
|
||||
</div>
|
||||
<div id="view_private_key" style="display: none" class="card text-white bg-dark mb-3">
|
||||
<h5 class="card-header">Private key</h5>
|
||||
<div class="card-header">
|
||||
<div class="form-group row">
|
||||
<div class="col-md-6 w-50">
|
||||
<button type="button" class="btn btn-success w-100" onclick="copy_text('private_key')">Copy</button>
|
||||
</div>
|
||||
<div class="col-md-6 w-50">
|
||||
<form class="text-center" method="POST" action="/account/private_key">
|
||||
<input type="submit" name="submit" value="QR code" class="btn btn-success w-100">
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<h6 class="card-text">{{ .PrivateKey }}</h6>
|
||||
</div>
|
||||
</div>
|
||||
<div id="input_password" style="display: none" class="form-group">
|
||||
<form id='password-form' class="text-center" method="POST" action="/account">
|
||||
<div class="form-group">
|
||||
<input id="username" type='text' class='form-control bg-dark text-light' name='username' placeholder='Username'>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<input id="password" type='password' class='form-control bg-dark text-light' name='password' placeholder='Password'>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<input type="submit" name="delete" value="Confirm deletion " class="btn btn-warning w-100">
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
<div style="opacity:0">
|
||||
<input id="private_key" type="text" value="{{ .PrivateKey }}">
|
||||
<input id="public_key" type="text" value="{{ .PublicKey }}">
|
||||
</div>
|
||||
{{ end }}
|
||||
{{ define "title" }}
|
||||
Account
|
||||
{{ end }}
|
||||
|
||||
{{ define "main" }}
|
||||
<div id="message_copy" style="display: none" class="text-light mx-auto">
|
||||
<div class="alert alert-success" role="alert">
|
||||
<button type="button" class="close" onclick="close_block('message_copy')">
|
||||
<span>×</span>
|
||||
</button>
|
||||
Key copied
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group row">
|
||||
<div class="col-md-6 w-50">
|
||||
<button type="button" class="btn btn-secondary divtext w-100" disabled>{{ .Auth }}</button>
|
||||
</div>
|
||||
<div class="col-md-6 w-50">
|
||||
<button type="button" class="btn btn-danger w-100" onclick="view_block('input_password'); clear_value('username'); clear_value('password'); close_block('view_private_key'); close_block('view_public_key')">Delete account</button>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group row">
|
||||
<div class="col-md-6 w-50">
|
||||
<button type="button" class="btn btn-info w-100" onclick="view_block('view_public_key'); close_block('view_private_key'); close_block('input_password')">Public key</button>
|
||||
</div>
|
||||
<div class="col-md-6 w-50">
|
||||
<button type="button" class="btn btn-info w-100" onclick="view_block('view_private_key'); close_block('view_public_key'); close_block('input_password')">Private key</button>
|
||||
</div>
|
||||
</div>
|
||||
<div id="view_public_key" style="display: none" class="card text-white bg-dark mb-3">
|
||||
<h5 class="card-header">Public key</h5>
|
||||
<div class="card-header">
|
||||
<div class="form-group row">
|
||||
<div class="col-md-6 w-50">
|
||||
<button type="button" class="btn btn-success w-100" onclick="copy_text('public_key')">Copy</button>
|
||||
</div>
|
||||
<div class="col-md-6 w-50">
|
||||
<form class="text-center" method="POST" action="/account/public_key">
|
||||
<input type="submit" name="submit" value="QR code" class="btn btn-success w-100">
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<h6 class="card-text">{{ .PublicKey }}</h6>
|
||||
</div>
|
||||
</div>
|
||||
<div id="view_private_key" style="display: none" class="card text-white bg-dark mb-3">
|
||||
<h5 class="card-header">Private key</h5>
|
||||
<div class="card-header">
|
||||
<div class="form-group row">
|
||||
<div class="col-md-6 w-50">
|
||||
<button type="button" class="btn btn-success w-100" onclick="copy_text('private_key')">Copy</button>
|
||||
</div>
|
||||
<div class="col-md-6 w-50">
|
||||
<form class="text-center" method="POST" action="/account/private_key">
|
||||
<input type="submit" name="submit" value="QR code" class="btn btn-success w-100">
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<h6 class="card-text">{{ .PrivateKey }}</h6>
|
||||
</div>
|
||||
</div>
|
||||
<div id="input_password" style="display: none" class="form-group">
|
||||
<form id='password-form' class="text-center" method="POST" action="/account">
|
||||
<div class="form-group">
|
||||
<input id="username" type='text' class='form-control bg-dark text-light' name='username' placeholder='Username'>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<input id="password" type='password' class='form-control bg-dark text-light' name='password' placeholder='Password'>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<input type="submit" name="delete" value="Confirm deletion " class="btn btn-warning w-100">
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
<div style="opacity:0">
|
||||
<input id="private_key" type="text" value="{{ .PrivateKey }}">
|
||||
<input id="public_key" type="text" value="{{ .PublicKey }}">
|
||||
</div>
|
||||
{{ end }}
|
||||
|
||||
@ -1,71 +1,71 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<title>{{ template "title" . }}</title>
|
||||
<meta charset="utf-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<link rel="stylesheet" type="text/css" href="/static/css/bootstrap.css">
|
||||
<script type="text/javascript" src="/static/js/main.js"></script>
|
||||
<script type="text/javascript" src="/static/js/jquery.js"></script>
|
||||
<script type="text/javascript" src="/static/js/bootstrap.js"></script>
|
||||
</head>
|
||||
<body class="bg-dark">
|
||||
<header>
|
||||
<nav class="navbar navbar-expand-lg navbar-dark py-1 bg-dark fixed-top" id="mainNav">
|
||||
<div class="container">
|
||||
<a href="/" class="navbar-brand js-scroll-trigger" exact><h4>HES</h4></a>
|
||||
<button class="navbar-toggler" type="button" data-toggle="collapse" data-target="#navbarResponsive" aria-controls="navbarResponsive" aria-expanded="false" aria-label="Toggle navigation">
|
||||
<span class="navbar-toggler-icon"></span>
|
||||
</button>
|
||||
<div class="collapse navbar-collapse" id="navbarResponsive">
|
||||
<ul class="navbar-nav">
|
||||
<li class="nav-item" data-toggle="collapse">
|
||||
<a href="/network" data-target=".navbar-collapse.show" class="nav-link js-scroll-trigger"><h5>Network</h5></a>
|
||||
</li>
|
||||
</ul>
|
||||
<ul class="navbar-nav ml-auto">
|
||||
{{ if .Auth }}
|
||||
<li class="nav-item" data-toggle="collapse">
|
||||
<a href="/account" data-target=".navbar-collapse.show" class="nav-link js-scroll-trigger"><h5>Account</h5></a>
|
||||
</li>
|
||||
<li class="nav-item" data-toggle="collapse">
|
||||
<a href="/signout" ata-target=".navbar-collapse.show" class="nav-link js-scroll-trigger"><h5>Signout</h5></a>
|
||||
</li>
|
||||
{{ else }}
|
||||
<li class="nav-item" data-toggle="collapse">
|
||||
<a href="/signin" data-target=".navbar-collapse.show" class="nav-link js-scroll-trigger"><h5>Signin</h5></a>
|
||||
</li>
|
||||
<li class="nav-item" data-toggle="collapse">
|
||||
<a href="/signup" data-target=".navbar-collapse.show" class="nav-link js-scroll-trigger"><h5>Signup</h5></a>
|
||||
</li>
|
||||
{{ end }}
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</nav>
|
||||
<br><br><br>
|
||||
</header>
|
||||
<main>
|
||||
<div class="py-3 bg-dark">
|
||||
<h2 class="text-secondary text-center">Hidden Email Service</h2>
|
||||
</div>
|
||||
<div class="text-light col-md-8 mx-auto">
|
||||
{{ if .Result }}
|
||||
{{ if (eq .Return 1 )}}
|
||||
<div class="alert alert-danger" role="alert">
|
||||
{{ else if (eq .Return 2 )}}
|
||||
<div class="alert alert-warning" role="alert">
|
||||
{{ else }}
|
||||
<div class="alert alert-success" role="alert">
|
||||
{{ end }}
|
||||
<button type="button" class="close" data-dismiss="alert" aria-label="Close">
|
||||
<span aria-hidden="true">×</span>
|
||||
</button>
|
||||
{{ .Result }}
|
||||
</div>
|
||||
{{ end }}
|
||||
{{ template "main" . }}
|
||||
</div>
|
||||
</main>
|
||||
</body>
|
||||
</html>
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<title>{{ template "title" . }}</title>
|
||||
<meta charset="utf-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<link rel="stylesheet" type="text/css" href="/static/css/bootstrap.css">
|
||||
<script type="text/javascript" src="/static/js/main.js"></script>
|
||||
<script type="text/javascript" src="/static/js/jquery.js"></script>
|
||||
<script type="text/javascript" src="/static/js/bootstrap.js"></script>
|
||||
</head>
|
||||
<body class="bg-dark">
|
||||
<header>
|
||||
<nav class="navbar navbar-expand-lg navbar-dark py-1 bg-dark fixed-top" id="mainNav">
|
||||
<div class="container">
|
||||
<a href="/" class="navbar-brand js-scroll-trigger" exact><h4>HES</h4></a>
|
||||
<button class="navbar-toggler" type="button" data-toggle="collapse" data-target="#navbarResponsive" aria-controls="navbarResponsive" aria-expanded="false" aria-label="Toggle navigation">
|
||||
<span class="navbar-toggler-icon"></span>
|
||||
</button>
|
||||
<div class="collapse navbar-collapse" id="navbarResponsive">
|
||||
<ul class="navbar-nav">
|
||||
<li class="nav-item" data-toggle="collapse">
|
||||
<a href="/network" data-target=".navbar-collapse.show" class="nav-link js-scroll-trigger"><h5>Network</h5></a>
|
||||
</li>
|
||||
</ul>
|
||||
<ul class="navbar-nav ml-auto">
|
||||
{{ if .Auth }}
|
||||
<li class="nav-item" data-toggle="collapse">
|
||||
<a href="/account" data-target=".navbar-collapse.show" class="nav-link js-scroll-trigger"><h5>Account</h5></a>
|
||||
</li>
|
||||
<li class="nav-item" data-toggle="collapse">
|
||||
<a href="/signout" ata-target=".navbar-collapse.show" class="nav-link js-scroll-trigger"><h5>Signout</h5></a>
|
||||
</li>
|
||||
{{ else }}
|
||||
<li class="nav-item" data-toggle="collapse">
|
||||
<a href="/signin" data-target=".navbar-collapse.show" class="nav-link js-scroll-trigger"><h5>Signin</h5></a>
|
||||
</li>
|
||||
<li class="nav-item" data-toggle="collapse">
|
||||
<a href="/signup" data-target=".navbar-collapse.show" class="nav-link js-scroll-trigger"><h5>Signup</h5></a>
|
||||
</li>
|
||||
{{ end }}
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</nav>
|
||||
<br><br><br>
|
||||
</header>
|
||||
<main>
|
||||
<div class="py-3 bg-dark">
|
||||
<h2 class="text-secondary text-center">Hidden Email Service</h2>
|
||||
</div>
|
||||
<div class="text-light col-md-8 mx-auto">
|
||||
{{ if .Result }}
|
||||
{{ if (eq .Return 1 )}}
|
||||
<div class="alert alert-danger" role="alert">
|
||||
{{ else if (eq .Return 2 )}}
|
||||
<div class="alert alert-warning" role="alert">
|
||||
{{ else }}
|
||||
<div class="alert alert-success" role="alert">
|
||||
{{ end }}
|
||||
<button type="button" class="close" data-dismiss="alert" aria-label="Close">
|
||||
<span aria-hidden="true">×</span>
|
||||
</button>
|
||||
{{ .Result }}
|
||||
</div>
|
||||
{{ end }}
|
||||
{{ template "main" . }}
|
||||
</div>
|
||||
</main>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
@ -1,35 +1,35 @@
|
||||
{{ define "title" }}
|
||||
Network.Connect
|
||||
{{ end }}
|
||||
|
||||
{{ define "main" }}
|
||||
<form class="text-center" method="POST" action="/network/connect">
|
||||
<div class="form-group">
|
||||
<input type="submit" name="check" value="Check connections" class="btn btn-info w-100">
|
||||
</div>
|
||||
</form>
|
||||
<form class="text-center" method="POST" action="/network/connect">
|
||||
<div class="form-group">
|
||||
<input type="text" class="form-control bg-dark text-light" name="hostname" placeholder="Hostname">
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<input type="password" class="form-control bg-dark text-light" name="password" placeholder="Password">
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<input type="submit" name="append" value="Append connection" class="btn btn-success w-100">
|
||||
</div>
|
||||
</form>
|
||||
{{ range .Connects }}
|
||||
<div class="form-group row">
|
||||
<div class="col-md-9 w-75">
|
||||
<button type="button" class="btn btn-secondary divtext w-100" disabled>{{ index . 0 }}</button>
|
||||
</div>
|
||||
<div class="col-md-3 w-25">
|
||||
<form class="text-center" method="POST" action="/network/connect">
|
||||
<input type="hidden" name="hostname" value="{{ index . 0 }}">
|
||||
<input type="submit" name="delete" value="Delete" class="btn btn-danger w-100">
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
{{ end }}
|
||||
{{ end }}
|
||||
{{ define "title" }}
|
||||
Network.Connect
|
||||
{{ end }}
|
||||
|
||||
{{ define "main" }}
|
||||
<form class="text-center" method="POST" action="/network/connect">
|
||||
<div class="form-group">
|
||||
<input type="submit" name="check" value="Check connections" class="btn btn-info w-100">
|
||||
</div>
|
||||
</form>
|
||||
<form class="text-center" method="POST" action="/network/connect">
|
||||
<div class="form-group">
|
||||
<input type="text" class="form-control bg-dark text-light" name="hostname" placeholder="Hostname">
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<input type="password" class="form-control bg-dark text-light" name="password" placeholder="Password">
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<input type="submit" name="append" value="Append connection" class="btn btn-success w-100">
|
||||
</div>
|
||||
</form>
|
||||
{{ range .Connects }}
|
||||
<div class="form-group row">
|
||||
<div class="col-md-9 w-75">
|
||||
<button type="button" class="btn btn-secondary divtext w-100" disabled>{{ index . 0 }}</button>
|
||||
</div>
|
||||
<div class="col-md-3 w-25">
|
||||
<form class="text-center" method="POST" action="/network/connect">
|
||||
<input type="hidden" name="hostname" value="{{ index . 0 }}">
|
||||
<input type="submit" name="delete" value="Delete" class="btn btn-danger w-100">
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
{{ end }}
|
||||
{{ end }}
|
||||
|
||||
@ -1,55 +1,55 @@
|
||||
{{ define "title" }}
|
||||
Network.Contact
|
||||
{{ end }}
|
||||
|
||||
{{ define "main" }}
|
||||
<div id="message_copy" style="display: none" class="text-light mx-auto">
|
||||
<div class="alert alert-success" role="alert">
|
||||
<button type="button" class="close" onclick="close_block('message_copy')">
|
||||
<span>×</span>
|
||||
</button>
|
||||
Key copied
|
||||
</div>
|
||||
</div>
|
||||
<form class="text-center" method="POST" action="/network/contact">
|
||||
<div class="form-group">
|
||||
{{ if .F2F }}
|
||||
<input type="submit" name="switchf2f" value="F2F" class="btn btn-success w-100">
|
||||
{{ else }}
|
||||
<input type="submit" name="switchf2f" value="F2F" class="btn btn-danger w-100">
|
||||
{{ end }}
|
||||
</div>
|
||||
</form>
|
||||
<form class="text-center" method="POST" action="/network/contact">
|
||||
<div class="form-group">
|
||||
<input type="text" class="form-control bg-dark text-light" name="nickname" placeholder="Nickname">
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<input type="text" class="form-control bg-dark text-light" name="public_key" placeholder="Public key">
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<input type="submit" name="append" value="Append contact" class="btn btn-success w-100">
|
||||
</div>
|
||||
</form>
|
||||
{{ range $key, $value := .Contacts }}
|
||||
<div class="form-group row">
|
||||
<div class="col-md-6 w-50">
|
||||
<button type="button" class="btn btn-secondary divtext w-100" disabled>{{ $key }}</button>
|
||||
</div>
|
||||
<div class="col-md-3 w-25">
|
||||
<button type="button" class="btn btn-success w-100" onclick="copy_text('public_key_' + '{{ $key }}')">Copy</button>
|
||||
</div>
|
||||
<div class="col-md-3 w-25">
|
||||
<form class="text-center" method="POST" action="/network/contact">
|
||||
<input type="hidden" name="public_key" value="{{ $value }}">
|
||||
<input type="submit" name="delete" value="Delete" class="btn btn-danger w-100">
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
{{ end }}
|
||||
{{ range $key, $value := .Contacts }}
|
||||
<div style="opacity:0">
|
||||
<input id="public_key_{{ $key }}" type="text" value="{{ $value }}">
|
||||
</div>
|
||||
{{ end }}
|
||||
{{ end }}
|
||||
{{ define "title" }}
|
||||
Network.Contact
|
||||
{{ end }}
|
||||
|
||||
{{ define "main" }}
|
||||
<div id="message_copy" style="display: none" class="text-light mx-auto">
|
||||
<div class="alert alert-success" role="alert">
|
||||
<button type="button" class="close" onclick="close_block('message_copy')">
|
||||
<span>×</span>
|
||||
</button>
|
||||
Key copied
|
||||
</div>
|
||||
</div>
|
||||
<form class="text-center" method="POST" action="/network/contact">
|
||||
<div class="form-group">
|
||||
{{ if .F2F }}
|
||||
<input type="submit" name="switchf2f" value="F2F" class="btn btn-success w-100">
|
||||
{{ else }}
|
||||
<input type="submit" name="switchf2f" value="F2F" class="btn btn-danger w-100">
|
||||
{{ end }}
|
||||
</div>
|
||||
</form>
|
||||
<form class="text-center" method="POST" action="/network/contact">
|
||||
<div class="form-group">
|
||||
<input type="text" class="form-control bg-dark text-light" name="nickname" placeholder="Nickname">
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<input type="text" class="form-control bg-dark text-light" name="public_key" placeholder="Public key">
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<input type="submit" name="append" value="Append contact" class="btn btn-success w-100">
|
||||
</div>
|
||||
</form>
|
||||
{{ range $key, $value := .Contacts }}
|
||||
<div class="form-group row">
|
||||
<div class="col-md-6 w-50">
|
||||
<button type="button" class="btn btn-secondary divtext w-100" disabled>{{ $key }}</button>
|
||||
</div>
|
||||
<div class="col-md-3 w-25">
|
||||
<button type="button" class="btn btn-success w-100" onclick="copy_text('public_key_' + '{{ $key }}')">Copy</button>
|
||||
</div>
|
||||
<div class="col-md-3 w-25">
|
||||
<form class="text-center" method="POST" action="/network/contact">
|
||||
<input type="hidden" name="public_key" value="{{ $value }}">
|
||||
<input type="submit" name="delete" value="Delete" class="btn btn-danger w-100">
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
{{ end }}
|
||||
{{ range $key, $value := .Contacts }}
|
||||
<div style="opacity:0">
|
||||
<input id="public_key_{{ $key }}" type="text" value="{{ $value }}">
|
||||
</div>
|
||||
{{ end }}
|
||||
{{ end }}
|
||||
|
||||
@ -1,23 +1,23 @@
|
||||
{{ define "title" }}
|
||||
HES
|
||||
{{ end }}
|
||||
|
||||
{{ define "main" }}
|
||||
<div class="card text-white bg-dark mb-3">
|
||||
<h5 class="card-header bg-secondary">HES project</h5>
|
||||
<div class="card-body">
|
||||
<h6 class="card-text">version: 1.1.10;</h6>
|
||||
<h6 class="card-text">project: <a target="_blank" class="text-info" href="https://github.com/Number571/HES">hes.git</a>;</h6>
|
||||
<h6 class="card-text">author: <a target="_blank" class="text-info" href="https://github.com/Number571">number571</a>;</h6>
|
||||
</div>
|
||||
</div>
|
||||
<div class="card text-white bg-dark mb-3">
|
||||
<h5 class="card-header bg-secondary">Sources</h5>
|
||||
<div class="card-body">
|
||||
<h6 class="card-text">protocol: <a target="_blank" class="text-info" href="https://github.com/Number571/gopeer">gopeer.git</a>;</h6>
|
||||
<h6 class="card-text">database: <a target="_blank" class="text-info" href="https://github.com/mattn/go-sqlite3">go-sqlite3.git</a>;</h6>
|
||||
<h6 class="card-text">design: <a target="_blank" class="text-info" href="https://github.com/twbs/bootstrap">bootstrap.git</a>;</h6>
|
||||
<h6 class="card-text">qrcode: <a target="_blank" class="text-info" href="https://github.com/boombuler/barcode">barcode.git</a>;</h6>
|
||||
</div>
|
||||
</div>
|
||||
{{ end }}
|
||||
{{ define "title" }}
|
||||
HES
|
||||
{{ end }}
|
||||
|
||||
{{ define "main" }}
|
||||
<div class="card text-white bg-dark mb-3">
|
||||
<h5 class="card-header bg-secondary">HES project</h5>
|
||||
<div class="card-body">
|
||||
<h6 class="card-text">version: 1.1.10;</h6>
|
||||
<h6 class="card-text">project: <a target="_blank" class="text-info" href="https://github.com/Number571/HES">hes.git</a>;</h6>
|
||||
<h6 class="card-text">author: <a target="_blank" class="text-info" href="https://github.com/Number571">number571</a>;</h6>
|
||||
</div>
|
||||
</div>
|
||||
<div class="card text-white bg-dark mb-3">
|
||||
<h5 class="card-header bg-secondary">Sources</h5>
|
||||
<div class="card-body">
|
||||
<h6 class="card-text">protocol: <a target="_blank" class="text-info" href="https://github.com/Number571/gopeer">gopeer.git</a>;</h6>
|
||||
<h6 class="card-text">database: <a target="_blank" class="text-info" href="https://github.com/mattn/go-sqlite3">go-sqlite3.git</a>;</h6>
|
||||
<h6 class="card-text">design: <a target="_blank" class="text-info" href="https://github.com/twbs/bootstrap">bootstrap.git</a>;</h6>
|
||||
<h6 class="card-text">qrcode: <a target="_blank" class="text-info" href="https://github.com/boombuler/barcode">barcode.git</a>;</h6>
|
||||
</div>
|
||||
</div>
|
||||
{{ end }}
|
||||
|
||||
@ -1,53 +1,53 @@
|
||||
{{ define "title" }}
|
||||
Network
|
||||
{{ end }}
|
||||
|
||||
{{ define "main" }}
|
||||
<div class="form-group row">
|
||||
<div class="col-md-6 w-50">
|
||||
<form class="text-center" method="GET" action="/network/contact">
|
||||
<input type="submit" name="submit" value="Contact" class="btn btn-success w-100">
|
||||
</form>
|
||||
</div>
|
||||
<div class="col-md-6 w-50">
|
||||
<form class="text-center" method="GET" action="/network/connect">
|
||||
<input type="submit" name="submit" value="Connect" class="btn btn-success w-100">
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group row">
|
||||
<div class="col-md-6 w-50">
|
||||
<form class="text-center" method="GET" action="/network/write">
|
||||
<input type="submit" name="submit" value="Write" class="btn btn-success w-100">
|
||||
</form>
|
||||
</div>
|
||||
<div class="col-md-6 w-50">
|
||||
<form class="text-center" method="POST" action="/network">
|
||||
<input type="submit" name="update" value="Update" class="btn btn-success w-100">
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group row">
|
||||
<div class="col-md-6 w-50">
|
||||
<form class="text-center" method="GET" action="/network">
|
||||
<input type="hidden" name="num" value="{{ dec .Page }}">
|
||||
<input {{ if (not .Page) }} disabled {{ end }} type="submit" name="page" value="Back" class="btn btn-info w-100">
|
||||
</form>
|
||||
</div>
|
||||
<div class="col-md-6 w-50">
|
||||
<form class="text-center" method="GET" action="/network">
|
||||
<input type="hidden" name="num" value="{{ inc .Page }}">
|
||||
<input {{ if (not .Emails) }} disabled {{ end }} type="submit" name="page" value="Next" class="btn btn-info w-100">
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
{{ range .Emails }}
|
||||
{{ $texts := (texts .)}}
|
||||
<div class="form-group">
|
||||
<form class="text-center" method="GET" action="/network/read">
|
||||
<input type="hidden" name="email" value="{{ .Id }}">
|
||||
<input type="submit" name="read" value="{{ .SenderName }} | {{ index $texts 0 }}" class="btn btn-secondary w-100">
|
||||
</form>
|
||||
</div>
|
||||
{{ end }}
|
||||
{{ end }}
|
||||
{{ define "title" }}
|
||||
Network
|
||||
{{ end }}
|
||||
|
||||
{{ define "main" }}
|
||||
<div class="form-group row">
|
||||
<div class="col-md-6 w-50">
|
||||
<form class="text-center" method="GET" action="/network/contact">
|
||||
<input type="submit" name="submit" value="Contact" class="btn btn-success w-100">
|
||||
</form>
|
||||
</div>
|
||||
<div class="col-md-6 w-50">
|
||||
<form class="text-center" method="GET" action="/network/connect">
|
||||
<input type="submit" name="submit" value="Connect" class="btn btn-success w-100">
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group row">
|
||||
<div class="col-md-6 w-50">
|
||||
<form class="text-center" method="GET" action="/network/write">
|
||||
<input type="submit" name="submit" value="Write" class="btn btn-success w-100">
|
||||
</form>
|
||||
</div>
|
||||
<div class="col-md-6 w-50">
|
||||
<form class="text-center" method="POST" action="/network">
|
||||
<input type="submit" name="update" value="Update" class="btn btn-success w-100">
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group row">
|
||||
<div class="col-md-6 w-50">
|
||||
<form class="text-center" method="GET" action="/network">
|
||||
<input type="hidden" name="num" value="{{ dec .Page }}">
|
||||
<input {{ if (not .Page) }} disabled {{ end }} type="submit" name="page" value="Back" class="btn btn-info w-100">
|
||||
</form>
|
||||
</div>
|
||||
<div class="col-md-6 w-50">
|
||||
<form class="text-center" method="GET" action="/network">
|
||||
<input type="hidden" name="num" value="{{ inc .Page }}">
|
||||
<input {{ if (not .Emails) }} disabled {{ end }} type="submit" name="page" value="Next" class="btn btn-info w-100">
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
{{ range .Emails }}
|
||||
{{ $texts := (texts .)}}
|
||||
<div class="form-group">
|
||||
<form class="text-center" method="GET" action="/network/read">
|
||||
<input type="hidden" name="email" value="{{ .Id }}">
|
||||
<input type="submit" name="read" value="{{ .SenderName }} | {{ index $texts 0 }}" class="btn btn-secondary w-100">
|
||||
</form>
|
||||
</div>
|
||||
{{ end }}
|
||||
{{ end }}
|
||||
|
||||
@ -1,91 +1,91 @@
|
||||
{{ define "title" }}
|
||||
Network.Read
|
||||
{{ end }}
|
||||
|
||||
{{ define "main" }}
|
||||
{{ if .Email }}
|
||||
{{ $texts := (texts .Email) }}
|
||||
{{ $files := (files .Email) }}
|
||||
<div id="message_copy" style="display: none" class="text-light mx-auto">
|
||||
<div class="alert alert-success" role="alert">
|
||||
<button type="button" class="close" onclick="close_block('message_copy')">
|
||||
<span>×</span>
|
||||
</button>
|
||||
Key copied
|
||||
</div>
|
||||
</div>
|
||||
<div class="card text-white bg-dark mb-3">
|
||||
<h5 class="card-header bg-secondary">Sender</h5>
|
||||
<div class="card-header">
|
||||
<div class="row">
|
||||
<h5 class="col-md-6 w-50">{{ .Email.SenderName }}</h5>
|
||||
<div class="col-md-6 w-50">
|
||||
<button type="button" class="btn btn-info w-100" onclick="view_block('view_public_key')">Public key</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div id="view_public_key" style="display: none" class="card text-white bg-dark mb-3">
|
||||
<h5 class="card-header">Public key</h5>
|
||||
<div class="card-header">
|
||||
<div class="form-group row">
|
||||
<div class="col-md-6 w-50">
|
||||
<button type="button" class="btn btn-success w-100" onclick="copy_text('public_key')">Copy</button>
|
||||
</div>
|
||||
<div class="col-md-6 w-50">
|
||||
<form class="text-center" method="POST" action="/network/read">
|
||||
<input type="hidden" name="public_key" value="{{ .Email.SenderPubl }}">
|
||||
<input type="submit" name="submit" value="QR code" class="btn btn-success w-100">
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<h6 class="card-text">{{ .Email.SenderPubl }}</h6>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="card text-white bg-dark mb-3">
|
||||
<h5 class="card-header bg-secondary">Email</h5>
|
||||
<h5 class="card-header bg-dark">{{ index $texts 0 }}</h5>
|
||||
<div class="card-body">
|
||||
{{ $msg := (split (index $texts 1) "\n") }}
|
||||
{{ range $msg }}
|
||||
<h6 class="card-text">{{ . }}</h6>
|
||||
{{ end }}
|
||||
</div>
|
||||
</div>
|
||||
{{ if $files }}
|
||||
<div class="card text-white bg-dark mb-3">
|
||||
<h5 class="card-header bg-secondary">Files</h5>
|
||||
<div class="card-body row">
|
||||
{{ range $files }}
|
||||
<div class="text-white bg-dark col-md-4 mb-3">
|
||||
<a title="Filename: {{ index . 0 }}" class="btn btn-success card-body text-truncate w-100" download="{{ index . 0 }}" href="data:text/plain;base64,{{ index . 1 }}">{{ index . 0 }}</a>
|
||||
</div>
|
||||
{{ end }}
|
||||
</div>
|
||||
</div>
|
||||
{{ end }}
|
||||
<div class="card text-white bg-dark mb-3">
|
||||
<h5 class="card-header bg-secondary">Time</h5>
|
||||
<div class="card-body">
|
||||
<h6 class="card-text">{{ .Email.Time }}</h6>
|
||||
</div>
|
||||
</div>
|
||||
<div class="card text-white bg-dark mb-3">
|
||||
<h5 class="card-header bg-secondary">Hash</h5>
|
||||
<div class="card-body">
|
||||
<h6 class="card-text">{{ .Email.Hash }}</h6>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<form class="text-center" method="POST" action="/network">
|
||||
<input type="hidden" name="email" value="{{ .Email.Hash }}">
|
||||
<input type="submit" name="delete" value="Delete" class="btn btn-danger w-100">
|
||||
</form>
|
||||
</div>
|
||||
<div style="opacity:0">
|
||||
<input id="public_key" type="text" value="{{ .Email.SenderPubl }}">
|
||||
</div>
|
||||
{{ end }}
|
||||
{{ end }}
|
||||
{{ define "title" }}
|
||||
Network.Read
|
||||
{{ end }}
|
||||
|
||||
{{ define "main" }}
|
||||
{{ if .Email }}
|
||||
{{ $texts := (texts .Email) }}
|
||||
{{ $files := (files .Email) }}
|
||||
<div id="message_copy" style="display: none" class="text-light mx-auto">
|
||||
<div class="alert alert-success" role="alert">
|
||||
<button type="button" class="close" onclick="close_block('message_copy')">
|
||||
<span>×</span>
|
||||
</button>
|
||||
Key copied
|
||||
</div>
|
||||
</div>
|
||||
<div class="card text-white bg-dark mb-3">
|
||||
<h5 class="card-header bg-secondary">Sender</h5>
|
||||
<div class="card-header">
|
||||
<div class="row">
|
||||
<h5 class="col-md-6 w-50">{{ .Email.SenderName }}</h5>
|
||||
<div class="col-md-6 w-50">
|
||||
<button type="button" class="btn btn-info w-100" onclick="view_block('view_public_key')">Public key</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div id="view_public_key" style="display: none" class="card text-white bg-dark mb-3">
|
||||
<h5 class="card-header">Public key</h5>
|
||||
<div class="card-header">
|
||||
<div class="form-group row">
|
||||
<div class="col-md-6 w-50">
|
||||
<button type="button" class="btn btn-success w-100" onclick="copy_text('public_key')">Copy</button>
|
||||
</div>
|
||||
<div class="col-md-6 w-50">
|
||||
<form class="text-center" method="POST" action="/network/read">
|
||||
<input type="hidden" name="public_key" value="{{ .Email.SenderPubl }}">
|
||||
<input type="submit" name="submit" value="QR code" class="btn btn-success w-100">
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<h6 class="card-text">{{ .Email.SenderPubl }}</h6>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="card text-white bg-dark mb-3">
|
||||
<h5 class="card-header bg-secondary">Email</h5>
|
||||
<h5 class="card-header bg-dark">{{ index $texts 0 }}</h5>
|
||||
<div class="card-body">
|
||||
{{ $msg := (split (index $texts 1) "\n") }}
|
||||
{{ range $msg }}
|
||||
<h6 class="card-text">{{ . }}</h6>
|
||||
{{ end }}
|
||||
</div>
|
||||
</div>
|
||||
{{ if $files }}
|
||||
<div class="card text-white bg-dark mb-3">
|
||||
<h5 class="card-header bg-secondary">Files</h5>
|
||||
<div class="card-body row">
|
||||
{{ range $files }}
|
||||
<div class="text-white bg-dark col-md-4 mb-3">
|
||||
<a title="Filename: {{ index . 0 }}" class="btn btn-success card-body text-truncate w-100" download="{{ index . 0 }}" href="data:text/plain;base64,{{ index . 1 }}">{{ index . 0 }}</a>
|
||||
</div>
|
||||
{{ end }}
|
||||
</div>
|
||||
</div>
|
||||
{{ end }}
|
||||
<div class="card text-white bg-dark mb-3">
|
||||
<h5 class="card-header bg-secondary">Time</h5>
|
||||
<div class="card-body">
|
||||
<h6 class="card-text">{{ .Email.Time }}</h6>
|
||||
</div>
|
||||
</div>
|
||||
<div class="card text-white bg-dark mb-3">
|
||||
<h5 class="card-header bg-secondary">Hash</h5>
|
||||
<div class="card-body">
|
||||
<h6 class="card-text">{{ .Email.Hash }}</h6>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<form class="text-center" method="POST" action="/network">
|
||||
<input type="hidden" name="email" value="{{ .Email.Hash }}">
|
||||
<input type="submit" name="delete" value="Delete" class="btn btn-danger w-100">
|
||||
</form>
|
||||
</div>
|
||||
<div style="opacity:0">
|
||||
<input id="public_key" type="text" value="{{ .Email.SenderPubl }}">
|
||||
</div>
|
||||
{{ end }}
|
||||
{{ end }}
|
||||
|
||||
@ -1,17 +1,17 @@
|
||||
{{ define "title" }}
|
||||
Signin
|
||||
{{ end }}
|
||||
|
||||
{{ define "main" }}
|
||||
<form class="text-center" method="POST" action="/signin">
|
||||
<div class="form-group">
|
||||
<input type="text" class="form-control bg-dark text-light" name="username" placeholder="Username">
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<input type="password" class="form-control bg-dark text-light" name="password" placeholder="Password">
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<input type="submit" name="submit" value="Enter to account" class="btn btn-success w-100">
|
||||
</div>
|
||||
</form>
|
||||
{{ define "title" }}
|
||||
Signin
|
||||
{{ end }}
|
||||
|
||||
{{ define "main" }}
|
||||
<form class="text-center" method="POST" action="/signin">
|
||||
<div class="form-group">
|
||||
<input type="text" class="form-control bg-dark text-light" name="username" placeholder="Username">
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<input type="password" class="form-control bg-dark text-light" name="password" placeholder="Password">
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<input type="submit" name="submit" value="Enter to account" class="btn btn-success w-100">
|
||||
</div>
|
||||
</form>
|
||||
{{ end }}
|
||||
@ -1,36 +1,36 @@
|
||||
{{ define "title" }}
|
||||
Signup
|
||||
{{ end }}
|
||||
|
||||
{{ define "main" }}
|
||||
<div class="alert alert-warning" role="alert">
|
||||
<button type="button" class="close" data-dismiss="alert" aria-label="Close">
|
||||
<span aria-hidden="true">×</span>
|
||||
</button>
|
||||
<div>
|
||||
The server stores all received information, including private keys.
|
||||
<br>
|
||||
Be careful when logging into the global network.
|
||||
</div>
|
||||
</div>
|
||||
<form id="feedbackForm" class="text-center" method="POST" action="/signup">
|
||||
<div class="form-group">
|
||||
<input type="text" class="form-control bg-dark text-light" name="username" placeholder="Username">
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<input type="password" class="form-control bg-dark text-light" name="password" placeholder="Password">
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<input type="password" class="form-control bg-dark text-light" name="password_repeat" placeholder="Repeat Password">
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<button type="button" class="btn btn-danger w-100" onclick="view_block('input_private_key'); clear_value('private_key')">Load private key</button>
|
||||
</div>
|
||||
<div id="input_private_key" style="display: none" class="form-group">
|
||||
<input type="password" id="private_key" class="form-control bg-dark text-light" name="private_key" placeholder="Private key">
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<input type="submit" name="submit" value="Create account" id="feedbackSubmit" class="btn btn-success w-100">
|
||||
</div>
|
||||
</form>
|
||||
{{ end }}
|
||||
{{ define "title" }}
|
||||
Signup
|
||||
{{ end }}
|
||||
|
||||
{{ define "main" }}
|
||||
<div class="alert alert-warning" role="alert">
|
||||
<button type="button" class="close" data-dismiss="alert" aria-label="Close">
|
||||
<span aria-hidden="true">×</span>
|
||||
</button>
|
||||
<div>
|
||||
The server stores all received information, including private keys.
|
||||
<br>
|
||||
Be careful when logging into the global network.
|
||||
</div>
|
||||
</div>
|
||||
<form id="feedbackForm" class="text-center" method="POST" action="/signup">
|
||||
<div class="form-group">
|
||||
<input type="text" class="form-control bg-dark text-light" name="username" placeholder="Username">
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<input type="password" class="form-control bg-dark text-light" name="password" placeholder="Password">
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<input type="password" class="form-control bg-dark text-light" name="password_repeat" placeholder="Repeat Password">
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<button type="button" class="btn btn-danger w-100" onclick="view_block('input_private_key'); clear_value('private_key')">Load private key</button>
|
||||
</div>
|
||||
<div id="input_private_key" style="display: none" class="form-group">
|
||||
<input type="password" id="private_key" class="form-control bg-dark text-light" name="private_key" placeholder="Private key">
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<input type="submit" name="submit" value="Create account" id="feedbackSubmit" class="btn btn-success w-100">
|
||||
</div>
|
||||
</form>
|
||||
{{ end }}
|
||||
|
||||
@ -1,28 +1,28 @@
|
||||
{{ define "title" }}
|
||||
Network.Write
|
||||
{{ end }}
|
||||
|
||||
{{ define "main" }}
|
||||
<form class="text-center" method="POST" action="/network/write" enctype="multipart/form-data">
|
||||
<div class="form-group">
|
||||
<select name="receiver" class="form-control bg-dark text-light">
|
||||
<option disabled>Receiver</option>
|
||||
{{ range $key, $value := .Contacts }}
|
||||
<option value="{{ $value }}">{{ $key }}</option>
|
||||
{{ end }}
|
||||
</select>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<input type="text" class="form-control bg-dark text-light" name="title" placeholder="Title">
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<textarea class="form-control bg-dark text-light" name="message" placeholder="Message"></textarea>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<input type="file" name="files" class="form-control bg-dark" multiple>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<input type="submit" name="submit" value="Send email" class="btn btn-success w-100">
|
||||
</div>
|
||||
</form>
|
||||
{{ end }}
|
||||
{{ define "title" }}
|
||||
Network.Write
|
||||
{{ end }}
|
||||
|
||||
{{ define "main" }}
|
||||
<form class="text-center" method="POST" action="/network/write" enctype="multipart/form-data">
|
||||
<div class="form-group">
|
||||
<select name="receiver" class="form-control bg-dark text-light">
|
||||
<option disabled>Receiver</option>
|
||||
{{ range $key, $value := .Contacts }}
|
||||
<option value="{{ $value }}">{{ $key }}</option>
|
||||
{{ end }}
|
||||
</select>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<input type="text" class="form-control bg-dark text-light" name="title" placeholder="Title">
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<textarea class="form-control bg-dark text-light" name="message" placeholder="Message"></textarea>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<input type="file" name="files" class="form-control bg-dark" multiple>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<input type="submit" name="submit" value="Send email" class="btn btn-success w-100">
|
||||
</div>
|
||||
</form>
|
||||
{{ end }}
|
||||
|
||||
Loading…
Reference in New Issue
Block a user