Combine auth/setup flow, update readme
This commit is contained in:
parent
f66ce030cf
commit
14056ff639
109
README.md
109
README.md
|
@ -1,103 +1,50 @@
|
|||
# hydroxide
|
||||
# hydroxide-push
|
||||
### *Forked from [Hydroxide](https://github.com/emersion/hydroxide)*
|
||||
|
||||
A third-party, open-source ProtonMail bridge. For power users only, designed to
|
||||
run on a server.
|
||||
## Push notifications for Proton Mail mobile via a UP provider
|
||||
|
||||
hydroxide supports CardDAV, IMAP and SMTP.
|
||||
|
||||
Rationale:
|
||||
|
||||
* No GUI, only a CLI (so it runs in headless environments)
|
||||
* Standard-compliant (we don't care about Microsoft Outlook)
|
||||
* Fully open-source
|
||||
|
||||
Feel free to join the IRC channel: #emersion on Libera Chat.
|
||||
|
||||
## How does it work?
|
||||
|
||||
hydroxide is a server that translates standard protocols (SMTP, IMAP, CardDAV)
|
||||
into ProtonMail API requests. It allows you to use your preferred e-mail clients
|
||||
and `git-send-email` with ProtonMail.
|
||||
|
||||
+-----------------+ +-------------+ ProtonMail +--------------+
|
||||
| | IMAP, SMTP | | API | |
|
||||
| E-mail client <-------------> hydroxide <--------------> ProtonMail |
|
||||
| | | | | |
|
||||
+-----------------+ +-------------+ +--------------+
|
||||
Protonmail depends on Google services to deliver push notifications,
|
||||
This is a stripped down version of [Hydroxide](https://github.com/emersion/hydroxide)
|
||||
to get notified of new mail. See original repo for details on operation.
|
||||
|
||||
## Setup
|
||||
|
||||
### Go
|
||||
Download (soon), build the binary or the container image or pull the container image yourself.
|
||||
Simplest way is to run the container image.
|
||||
|
||||
hydroxide is implemented in Go. Head to [Go website](https://golang.org) for
|
||||
setup information.
|
||||
Login and push gateway details are saved under `$HOME/.config/hydroxide`. The container
|
||||
image saves configuration under `/data`, so mount a named volume or host directory there.
|
||||
The examples below use a named volume.
|
||||
|
||||
### Installing
|
||||
|
||||
Start by installing hydroxide:
|
||||
If using Docker, substitute `podman` with `docker` in the examples.
|
||||
|
||||
Binary:
|
||||
```shell
|
||||
git clone https://github.com/emersion/hydroxide.git
|
||||
go build ./cmd/hydroxide
|
||||
./hydroxide-push auth your.proton@email.address
|
||||
```
|
||||
|
||||
Then you'll need to login to ProtonMail via hydroxide, so that hydroxide can
|
||||
retrieve e-mails from ProtonMail. You can do so with this command:
|
||||
|
||||
Container:
|
||||
```shell
|
||||
hydroxide auth <username>
|
||||
podman run -it --rm -v hydroxide-config:/data ghcr.io/0ranki/hydroxide-push auth your.proton@email.address
|
||||
```
|
||||
You will be prompted for the Proton account credentials and the details for the push server. Proton credentials are stored encrypted form.
|
||||
|
||||
Once you're logged in, a "bridge password" will be printed. Don't close your
|
||||
terminal yet, as this password is not stored anywhere by hydroxide and will be
|
||||
needed when configuring your e-mail client.
|
||||
|
||||
Your ProtonMail credentials are stored on disk encrypted with this bridge
|
||||
password (a 32-byte random password generated when logging in).
|
||||
|
||||
## Usage
|
||||
|
||||
hydroxide can be used in multiple modes.
|
||||
|
||||
> Don't start hydroxide multiple times, instead you can use `hydroxide serve`.
|
||||
> This requires ports 1025 (smtp), 1143 (imap), and 8080 (carddav).
|
||||
|
||||
### SMTP
|
||||
|
||||
To run hydroxide as an SMTP server:
|
||||
The auth flow generates a separate password for the bridge, which is stored in plaintext
|
||||
to `$HOME/.config/notify.json`. Unlike upstream `hydroxide`, there is no service listening on any port,
|
||||
all communications is internal to the program.
|
||||
|
||||
### Reconfigure push server
|
||||
Binary:
|
||||
```shell
|
||||
hydroxide smtp
|
||||
hydroxide-push setup-ntfy
|
||||
```
|
||||
|
||||
Once the bridge is started, you can configure your e-mail client with the
|
||||
following settings:
|
||||
|
||||
* Hostname: `localhost`
|
||||
* Port: 1025
|
||||
* Security: none
|
||||
* Username: your ProtonMail username
|
||||
* Password: the bridge password (not your ProtonMail password)
|
||||
|
||||
### CardDAV
|
||||
|
||||
You must setup an HTTPS reverse proxy to forward requests to `hydroxide`.
|
||||
|
||||
Container:
|
||||
```shell
|
||||
hydroxide carddav
|
||||
podman run -it --rm -v hydroxide-config:/data ghcr.io/0ranki/hydroxide-push setup-ntfy
|
||||
```
|
||||
You'll be asked for the base URL of the push server, and the topic. These will probably
|
||||
be combined to a single string in future versions.
|
||||
|
||||
Tested on GNOME (Evolution) and Android (DAVDroid).
|
||||
|
||||
### IMAP
|
||||
|
||||
⚠️ **Warning**: IMAP support is work-in-progress. Here be dragons.
|
||||
|
||||
For now, it only supports unencrypted local connections.
|
||||
|
||||
```shell
|
||||
hydroxide imap
|
||||
```
|
||||
**NOTE:** Authentication for the push endpoint is not yet supported.
|
||||
|
||||
## License
|
||||
|
||||
|
|
|
@ -74,6 +74,38 @@ func listenEventsAndNotify(addr string, debug bool, authManager *auth.Manager, e
|
|||
return nil
|
||||
}
|
||||
|
||||
func setupNtfy() {
|
||||
err := cfg.Read()
|
||||
if err != nil {
|
||||
fmt.Println(err)
|
||||
}
|
||||
var n string
|
||||
if cfg.URL != "" && cfg.Topic != "" {
|
||||
fmt.Printf("Current push endpoint: %s\n", cfg.String())
|
||||
n = "new "
|
||||
}
|
||||
scanner := bufio.NewScanner(os.Stdin)
|
||||
fmt.Printf("Input %spush server URL (e.g. 'http://ntfy.sh') : ", n)
|
||||
scanner.Scan()
|
||||
cfg.URL = scanner.Text()
|
||||
scanner = bufio.NewScanner(os.Stdin)
|
||||
fmt.Printf("Input push topic (e.g. my-proton-notifications): ")
|
||||
scanner.Scan()
|
||||
cfg.Topic = scanner.Text()
|
||||
fmt.Printf("Using URL %s\n", cfg.String())
|
||||
err = cfg.Save()
|
||||
if err != nil {
|
||||
fmt.Println(err)
|
||||
os.Exit(1)
|
||||
}
|
||||
err = ntfy.LoginBridge(&cfg)
|
||||
if err != nil {
|
||||
fmt.Println(err)
|
||||
os.Exit(1)
|
||||
}
|
||||
fmt.Println("Notification configuration saved")
|
||||
}
|
||||
|
||||
const usage = `usage: hydroxide-push [options...] <command>
|
||||
Commands:
|
||||
auth <username> Login to ProtonMail via hydroxide
|
||||
|
@ -211,8 +243,15 @@ func main() {
|
|||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
fmt.Println("Bridge password:", bridgePassword)
|
||||
cfg.BridgePw = bridgePassword
|
||||
reply, err := ntfy.AskToSaveBridgePw(&cfg)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
if reply != "yes" {
|
||||
fmt.Println("Bridge password:", bridgePassword)
|
||||
}
|
||||
setupNtfy()
|
||||
case "status":
|
||||
usernames, err := auth.ListUsernames()
|
||||
if err != nil {
|
||||
|
@ -229,30 +268,7 @@ func main() {
|
|||
}
|
||||
|
||||
case "setup-ntfy":
|
||||
err = cfg.Read()
|
||||
if err != nil {
|
||||
fmt.Println(err)
|
||||
}
|
||||
var new string
|
||||
if cfg.URL != "" && cfg.Topic != "" {
|
||||
fmt.Printf("Current push endpoint: %s\n", cfg.String())
|
||||
new = "new "
|
||||
}
|
||||
scanner := bufio.NewScanner(os.Stdin)
|
||||
fmt.Printf("Input %spush server URL (e.g. 'http://ntfy.sh') : ", new)
|
||||
scanner.Scan()
|
||||
cfg.URL = scanner.Text()
|
||||
scanner = bufio.NewScanner(os.Stdin)
|
||||
fmt.Printf("Input push topic (e.g. my-proton-notifications): ")
|
||||
scanner.Scan()
|
||||
cfg.Topic = scanner.Text()
|
||||
fmt.Printf("Using URL %s\n", cfg.String())
|
||||
err = cfg.Save()
|
||||
if err != nil {
|
||||
fmt.Println(err)
|
||||
os.Exit(1)
|
||||
}
|
||||
fmt.Println("Notification configuration saved")
|
||||
setupNtfy()
|
||||
case "notify":
|
||||
authManager := auth.NewManager(newClient)
|
||||
eventsManager := events.NewManager()
|
||||
|
|
46
ntfy/ntfy.go
46
ntfy/ntfy.go
|
@ -3,6 +3,7 @@ package ntfy
|
|||
import (
|
||||
"bufio"
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
"github.com/0ranki/hydroxide-push/auth"
|
||||
"github.com/0ranki/hydroxide-push/config"
|
||||
|
@ -63,6 +64,34 @@ func (cfg *NtfyConfig) Read() error {
|
|||
return nil
|
||||
}
|
||||
|
||||
func AskToSaveBridgePw(cfg *NtfyConfig) (string, error) {
|
||||
scanner := bufio.NewScanner(os.Stdin)
|
||||
//fmt.Printf("Save bridge password to config?\nThe password is stored in plain text, but (yes/n): ")
|
||||
//scanner.Scan()
|
||||
//if scanner.Text() == "yes" {
|
||||
if err := cfg.Save(); err != nil {
|
||||
return "", errors.New("failed to save notification config")
|
||||
}
|
||||
//}
|
||||
return scanner.Text(), nil
|
||||
}
|
||||
|
||||
func LoginBridge(cfg *NtfyConfig) error {
|
||||
if cfg.BridgePw == "" {
|
||||
cfg.BridgePw = os.Getenv("HYDROXIDE_BRIDGE_PASSWORD")
|
||||
}
|
||||
if cfg.BridgePw == "" {
|
||||
scanner := bufio.NewScanner(os.Stdin)
|
||||
fmt.Printf("Bridge password: ")
|
||||
scanner.Scan()
|
||||
cfg.BridgePw = scanner.Text()
|
||||
_, err := AskToSaveBridgePw(cfg)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
func Login(cfg *NtfyConfig, be backend.Backend) {
|
||||
//time.Sleep(1 * time.Second)
|
||||
c, _ := net.ResolveIPAddr("ip", "127.0.0.1")
|
||||
|
@ -88,20 +117,9 @@ func Login(cfg *NtfyConfig, be backend.Backend) {
|
|||
log.Fatalln("then setup ntfy using " + executable + "setup-ntfy")
|
||||
}
|
||||
if cfg.BridgePw == "" {
|
||||
cfg.BridgePw = os.Getenv("HYDROXIDE_BRIDGE_PASSWORD")
|
||||
}
|
||||
if cfg.BridgePw == "" {
|
||||
scanner := bufio.NewScanner(os.Stdin)
|
||||
fmt.Printf("Bridge password: ")
|
||||
scanner.Scan()
|
||||
cfg.BridgePw = scanner.Text()
|
||||
scanner = bufio.NewScanner(os.Stdin)
|
||||
fmt.Printf("Save password to config? The password is stored in plain text! (yes/n): ")
|
||||
scanner.Scan()
|
||||
if scanner.Text() == "yes" {
|
||||
if err = cfg.Save(); err != nil {
|
||||
log.Fatal("failed to save notification config")
|
||||
}
|
||||
err = LoginBridge(cfg)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
}
|
||||
_, err = be.Login(&conn, usernames[0], cfg.BridgePw)
|
||||
|
|
Loading…
Reference in New Issue