-
Notifications
You must be signed in to change notification settings - Fork 6
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat(vpn-qr-code): add support of qr-code vpn login and qr-code login…
… based wssocks connection In this commit, we add full implementation of qr-code vpn login. In the fyne based client, we can click "start" button -> show qr code window -> scan code -> connect to wssocks server. In the go code level, we add the full implementation of qr-code based vpn login (see document in `plugins/vpn/qr-code-docs.md`). However, qr code vpn login is only implemented on fyne based client. The cli client and swiftui client do not support qr code vpn login currently. re #25
- Loading branch information
Showing
5 changed files
with
255 additions
and
75 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,19 +1,78 @@ | ||
package main | ||
|
||
import ( | ||
"bytes" | ||
"context" | ||
"errors" | ||
"fmt" | ||
"fyne.io/fyne/v2" | ||
"fyne.io/fyne/v2/canvas" | ||
"fyne.io/fyne/v2/container" | ||
"fyne.io/fyne/v2/widget" | ||
"github.com/genshen/wssocks-plugin-ustb/plugins/vpn" | ||
log "github.com/sirupsen/logrus" | ||
"github.com/skip2/go-qrcode" | ||
"net/http" | ||
"time" | ||
) | ||
|
||
// LoadQRImage shows QR image for login | ||
func LoadQRImage() *canvas.Image { | ||
if qrImgReader, err := vpn.LoadQrAuthImage(); err != nil { | ||
log.Println(err) // todo | ||
return nil | ||
type FyneQrCodeAuth struct { | ||
appRef *fyne.App | ||
} | ||
|
||
func newQrCodeAuth(app *fyne.App) vpn.QrCodeAuth { | ||
return &FyneQrCodeAuth{ | ||
appRef: app, | ||
} | ||
} | ||
|
||
func (q *FyneQrCodeAuth) ShowQrCodeAndWait(client *http.Client, cookies []*http.Cookie, qr vpn.QrImg) ([]*http.Cookie, error) { | ||
// generate qr code from image | ||
qrPng, err := qrcode.Encode(qr.GenQrCodeContent(), qrcode.Medium, 256) | ||
if err != nil { | ||
return nil, err | ||
} | ||
buf := bytes.NewReader(qrPng) | ||
QrImage := canvas.NewImageFromReader(buf, "qr.png") | ||
QrImage.FillMode = canvas.ImageFillOriginal | ||
|
||
scanned := make(chan bool, 1) // signal of qr code scan finished | ||
// show qr code window | ||
qrAuthWindow := (*q.appRef).NewWindow("QR Code vpn auth") | ||
qrAuthWindow.SetContent(container.NewVBox( | ||
QrImage, | ||
widget.NewLabel("scan QR code, and then click button `Finish` "), | ||
widget.NewButton("Finish", func() { | ||
scanned <- true | ||
}), | ||
)) | ||
qrAuthWindow.Show() | ||
|
||
// wait qr code scanned or time out | ||
// scan the qr code in 30 seconds. Otherwise, an error of Timeout will return. | ||
ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second) | ||
defer cancel() | ||
|
||
select { | ||
case <-scanned: | ||
qrAuthWindow.Close() | ||
return WaitStatus(client, cookies, qr) | ||
case <-ctx.Done(): | ||
qrAuthWindow.Close() | ||
return nil, errors.New("scan QR code canceled due to timeout") | ||
} | ||
} | ||
|
||
func WaitStatus(client *http.Client, cookies []*http.Cookie, qr vpn.QrImg) ([]*http.Cookie, error) { | ||
// todo: set http cancel, after timeout | ||
if state, err := vpn.WaitQrState(qr.Sid); err != nil { | ||
fmt.Println(err) | ||
return nil, err | ||
} else { | ||
image := canvas.NewImageFromReader(qrImgReader, "qr.png") | ||
image.FillMode = canvas.ImageFillOriginal | ||
return image | ||
if err = vpn.RedirectToLogin(client, cookies, qr.Config.AppID, state, qr.Config.RandToken); err != nil { | ||
fmt.Println(err) | ||
return nil, err | ||
} | ||
} | ||
|
||
return nil, nil | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,19 @@ | ||
## Documentation of implementation of USTB vpn qr-code login | ||
|
||
Starting from 2024/05, the ustb-vpn adds QR-code login. | ||
The authentication process can be described as following: | ||
1. In vpn login page's html code, (e.g., https://n.ustb.edu.cn/login), it contains an iframe of url: | ||
"https://sis.ustb.edu.cn/connect/qrpage?appid=****&return_url=https%3A%2F%2Fn.ustb.edu.cn%2Flogin%3Fustb_sis%3Dtrue&rand_token=***&embed_flag=1", | ||
In the iframe, it contains a QR-code (qr code image url: https://sis.ustb.edu.cn/connect/qrimg?sid=${SID}, and QR content is: | ||
https://sis.ustb.edu.cn/auth?sid=${SID). | ||
2. While waiting for WeChat QR scanning, it sends a requests of `https://sis.ustb.edu.cn/connect/state?sid=${SID}` (state request) and waits for its response. | ||
3. If WeChat QR scanning is finished, the request in step 2. will response json data `{"state":200,"data":"39ff2a42e4474e70228b6337e159da8d"}`. | ||
4. The `data` field in above json data is used as **auth_code**. | ||
5. A callback redirect of url `https://n.ustb.edu.cn/login?ustb_sis=true&appid=***&auth_code=***&rand_token=***` will be generated and requested. | ||
6. QR-code login finished. | ||
|
||
In our go side implementation, we need: | ||
1) Parse _appid_, _rand\_token_, and _SID_ in the iframe url or its html content. | ||
2) Generate QR code images: use _SID_ to generate the QR code by using package github.com/skip2/go-qrcode. | ||
3) Send state request and waits for its response. After its response arrives, we can obtain the _auth_code_. | ||
4) Send callback redirect request to finish QR-code login. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.