add compile

This commit is contained in:
number571 2021-05-21 23:00:07 -04:00
parent 93ffe80981
commit bd6f8f4f70
30 changed files with 15415 additions and 15363 deletions

13
.gitignore vendored
View File

@ -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
View File

@ -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.

View File

@ -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
View File

@ -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"/>

File diff suppressed because it is too large Load Diff

1580
client.go

File diff suppressed because it is too large Load Diff

View File

@ -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
View 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;
}

View File

@ -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)
}

View File

@ -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
View File

@ -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
View File

@ -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=

View File

@ -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
}

View File

@ -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
}

View File

@ -1,9 +1,9 @@
{
"pasw": "",
"conns": [
[
"addr",
"pasw"
]
]
{
"pasw": "",
"conns": [
[
"addr",
"pasw"
]
]
}

342
server.go
View File

@ -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)
}

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because one or more lines are too long

View File

@ -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 = "";
}

View File

@ -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>&times;</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>&times;</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 }}

View File

@ -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">&times;</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">&times;</span>
</button>
{{ .Result }}
</div>
{{ end }}
{{ template "main" . }}
</div>
</main>
</body>
</html>

View File

@ -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 }}

View File

@ -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>&times;</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>&times;</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 }}

View File

@ -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 }}

View File

@ -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 }}

View File

@ -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>&times;</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>&times;</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 }}

View File

@ -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 }}

View File

@ -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">&times;</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">&times;</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 }}

View File

@ -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 }}