blob: fa013c904a010df83102cdfd361180f2b39fdd12 [file] [log] [blame]
giolekva313ee2b2021-12-15 15:17:29 +04001package main
2
3import (
giolekvaf58a7692021-12-15 18:05:39 +04004 "bytes"
5 "encoding/json"
giolekva313ee2b2021-12-15 15:17:29 +04006 "flag"
7 "fmt"
giolekvaf58a7692021-12-15 18:05:39 +04008 "image"
9 "image/png"
giolekva52da88a2021-12-17 18:08:25 +040010 "time"
giolekva313ee2b2021-12-15 15:17:29 +040011
12 "gioui.org/app"
giolekva96202c52021-12-18 12:45:34 +040013 "gioui.org/font/gofont"
giolekva313ee2b2021-12-15 15:17:29 +040014 "gioui.org/io/system"
15 "gioui.org/layout"
16 "gioui.org/op"
17 "gioui.org/unit"
giolekva96202c52021-12-18 12:45:34 +040018 "gioui.org/widget/material"
giolekvaf58a7692021-12-15 18:05:39 +040019 "github.com/skip2/go-qrcode"
giolekva313ee2b2021-12-15 15:17:29 +040020)
21
giolekvaf58a7692021-12-15 18:05:39 +040022var vpnApiAddr = flag.String("vpn-api-addr", "", "VPN API server address")
giolekva313ee2b2021-12-15 15:17:29 +040023
giolekvaf58a7692021-12-15 18:05:39 +040024var p *processor
25
26type processor struct {
27 vc VPNClient
28 app App
29 ui *UI
30
31 inviteQrCh chan image.Image
32 inviteQrScannedCh chan []byte
giolekva52da88a2021-12-17 18:08:25 +040033
34 onConnectCh chan interface{}
35 onDisconnectCh chan interface{}
giolekva313ee2b2021-12-15 15:17:29 +040036}
37
giolekvaf58a7692021-12-15 18:05:39 +040038func newProcessor() *processor {
giolekva96202c52021-12-18 12:45:34 +040039 th := material.NewTheme(gofont.Collection())
giolekvaf58a7692021-12-15 18:05:39 +040040 return &processor{
41 vc: NewDirectVPNClient(*vpnApiAddr),
42 app: createApp(),
giolekva96202c52021-12-18 12:45:34 +040043 ui: NewUI(th),
giolekvaf58a7692021-12-15 18:05:39 +040044 inviteQrCh: make(chan image.Image, 1),
45 inviteQrScannedCh: make(chan []byte, 1),
giolekva52da88a2021-12-17 18:08:25 +040046 onConnectCh: make(chan interface{}, 1),
47 onDisconnectCh: make(chan interface{}, 1),
giolekvaf58a7692021-12-15 18:05:39 +040048 }
49}
50
51func (p *processor) InviteQRCodeScanned(code []byte) {
52 p.inviteQrScannedCh <- code
53}
54
giolekva52da88a2021-12-17 18:08:25 +040055func (p *processor) ConnectRequested(service interface{}) {
56 go func() {
57 time.Sleep(1 * time.Second)
58 p.onConnectCh <- service
59 }()
60}
61
62func (p *processor) DisconnectRequested(service interface{}) {
63 p.onDisconnectCh <- service
64}
65
giolekvaf58a7692021-12-15 18:05:39 +040066func (p *processor) run() error {
giolekva313ee2b2021-12-15 15:17:29 +040067 w := app.NewWindow(
68 app.Size(unit.Px(1500), unit.Px(1500)),
69 app.Title("PCloud"),
70 )
71 var ops op.Ops
72 for {
73 select {
74 case e := <-w.Events():
75 switch e := e.(type) {
76 case app.ViewEvent:
giolekvaf58a7692021-12-15 18:05:39 +040077 if err := p.app.OnView(e); err != nil {
giolekva313ee2b2021-12-15 15:17:29 +040078 return err
79 } else {
80 w.Invalidate()
81 }
82 case *system.CommandEvent:
83 if e.Type == system.CommandBack {
giolekvaf58a7692021-12-15 18:05:39 +040084 if p.ui.OnBack() {
giolekva313ee2b2021-12-15 15:17:29 +040085 e.Cancel = true
86 w.Invalidate()
87 }
88 }
89 case system.FrameEvent:
90 gtx := layout.NewContext(&ops, e)
giolekvaf58a7692021-12-15 18:05:39 +040091 events := p.ui.Layout(gtx)
giolekva313ee2b2021-12-15 15:17:29 +040092 e.Frame(&ops)
giolekvaf58a7692021-12-15 18:05:39 +040093 if err := p.processUIEvents(events); err != nil {
giolekva313ee2b2021-12-15 15:17:29 +040094 return err
95 }
96 }
giolekvaf58a7692021-12-15 18:05:39 +040097 case img := <-p.inviteQrCh:
98 p.ui.InviteQRGenerated(img)
99 w.Invalidate()
100 case code := <-p.inviteQrScannedCh:
giolekva52da88a2021-12-17 18:08:25 +0400101 p.JoinNetworkAndConnect(code)
giolekva52da88a2021-12-17 18:08:25 +0400102 case s := <-p.onConnectCh:
giolekva52da88a2021-12-17 18:08:25 +0400103 if err := p.app.Connect(s); err != nil {
giolekva96202c52021-12-18 12:45:34 +0400104 return err
giolekva52da88a2021-12-17 18:08:25 +0400105 }
giolekva313ee2b2021-12-15 15:17:29 +0400106 }
107 }
108 return nil
109}
110
giolekvaf58a7692021-12-15 18:05:39 +0400111func (p *processor) processUIEvents(events []UIEvent) error {
112 for _, e := range events {
113 switch e.(type) {
114 case EventGetInviteQRCode:
115 go func() {
116 if img, err := p.generateInviteQRCode(); err == nil {
117 p.inviteQrCh <- img
118 } else {
119 // TODO(giolekva): do not panic
120 panic(err)
121 }
122 }()
123 case EventScanBarcode:
124 return p.app.LaunchBarcodeScanner()
125 default:
126 return fmt.Errorf("Unhandled event: %#v", e)
127 }
128 }
129 return nil
130}
131
132type qrCodeData struct {
133 VPNApiAddr string `json:"vpn_api_addr"`
134 Message []byte `json:"message"`
135 Signature []byte `json:"signature"`
136}
137
138func (p *processor) generateInviteQRCode() (image.Image, error) {
139 message := []byte("Hello PCloud")
140 signature, err := p.vc.Sign(message)
141 if err != nil {
142 return nil, err
143 }
144 c := qrCodeData{
145 p.vc.Address(),
146 message,
147 signature,
148 }
149 var data bytes.Buffer
150 if err := json.NewEncoder(&data).Encode(c); err != nil {
151 return nil, err
152 }
153 qr, err := qrcode.Encode(data.String(), qrcode.Medium, 1024)
154 if err != nil {
155 return nil, err
156 }
157 img, err := png.Decode(bytes.NewReader(qr))
158 if err != nil {
159 return nil, err
160 }
161 return img, nil
162}
163
164func (p *processor) JoinNetworkAndConnect(code []byte) {
165 var invite qrCodeData
166 if err := json.NewDecoder(bytes.NewReader(code)).Decode(&invite); err != nil {
167 panic(err)
168 }
169 config, err := p.vc.Join(invite.VPNApiAddr, invite.Message, invite.Signature)
170 if err != nil {
171 panic(err)
172 }
giolekva52da88a2021-12-17 18:08:25 +0400173 if err := p.app.StartVPN(config); err != nil {
174 panic(err)
175 }
giolekvaf58a7692021-12-15 18:05:39 +0400176}
177
giolekva313ee2b2021-12-15 15:17:29 +0400178func main() {
179 flag.Parse()
giolekvaf58a7692021-12-15 18:05:39 +0400180 p = newProcessor()
giolekva313ee2b2021-12-15 15:17:29 +0400181 go func() {
giolekvaf58a7692021-12-15 18:05:39 +0400182 if err := p.run(); err != nil {
giolekva313ee2b2021-12-15 15:17:29 +0400183 panic(err)
184 }
185 }()
186 app.Main()
187}
giolekvacc3ebcb2021-12-17 10:52:17 +0400188
189// fmt.Println(m["pki"])
190// c := nc.NewC(logrus.StandardLogger())
191// if err := c.LoadString(string(tmpl)); err != nil {
192// return nil, err
193// }
194// fmt.Println(c.Settings["pki"])
195// return c, nil