Skip to content

Commit

Permalink
Add AsSource func for represent key as Outline connection source
Browse files Browse the repository at this point in the history
  • Loading branch information
hteppl committed May 2, 2024
1 parent b5f8a65 commit 726dd2b
Showing 1 changed file with 56 additions and 17 deletions.
73 changes: 56 additions & 17 deletions outline.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,14 @@ package outlinevpn

import (
"crypto/tls"
"encoding/base64"
"encoding/json"
"errors"
"fmt"
"github.com/valyala/fasthttp"
"net/url"
"strconv"
"strings"
"time"
)

Expand All @@ -29,7 +33,7 @@ type OutlineKey struct {
// https://www.reddit.com/r/outlinevpn/wiki/index/dynamic_access_keys/
type OutlineConnectionSource struct {
Server string `json:"server"`
ServerPort uint `json:"server_port"`
ServerPort int `json:"server_port"`
Password string `json:"password"`
Method string `json:"method"`
}
Expand Down Expand Up @@ -81,7 +85,7 @@ func NewOutlineVPN(apiURL string, certSha256 string) (*OutlineVPN, error) {
}

// NewOutlineConnection creates a new Outline client connection source.
func NewOutlineConnection(server string, port uint, password string, method string) *OutlineConnectionSource {
func NewOutlineConnection(server string, port int, password string, method string) *OutlineConnectionSource {
return &OutlineConnectionSource{
Server: server,
ServerPort: port,
Expand Down Expand Up @@ -120,7 +124,7 @@ func (vpn *OutlineVPN) GetKeys() ([]OutlineKey, error) {
return keys.AccessKeys, nil
}

func (vpn *OutlineVPN) GetKey(id string) (OutlineKey, error) {
func (vpn *OutlineVPN) GetKey(id string) (*OutlineKey, error) {
request := fasthttp.AcquireRequest()
response := fasthttp.AcquireResponse()
defer fasthttp.ReleaseRequest(request)
Expand All @@ -132,20 +136,20 @@ func (vpn *OutlineVPN) GetKey(id string) (OutlineKey, error) {
request.SetRequestURI(fmt.Sprintf("%s/access-keys/%s", vpn.apiURL, id))
// Executing request
if err := vpn.session.DoTimeout(request, response, defaultTimeout); err != nil {
return result, err
return &result, err
}

// If key is added, status code always must be 200
if response.StatusCode() != fasthttp.StatusOK {
return result, errors.New("unable to retrieve keys")
return &result, errors.New("unable to retrieve keys")
}

// Trying unmarshal response body as `OutlineKey`
if err := json.Unmarshal(response.Body(), &result); err != nil {
return result, err
return &result, err
}

return result, nil
return &result, nil
}

func (vpn *OutlineVPN) AddKey(key *OutlineKey) (*OutlineKey, error) {
Expand Down Expand Up @@ -249,7 +253,7 @@ func (vpn *OutlineVPN) RenameKeyByID(id string, name string) error {
return nil
}

func (vpn *OutlineVPN) GetTransferMetrics() (BytesTransferred, error) {
func (vpn *OutlineVPN) GetTransferMetrics() (*BytesTransferred, error) {
request := fasthttp.AcquireRequest()
response := fasthttp.AcquireResponse()
defer fasthttp.ReleaseRequest(request)
Expand All @@ -261,23 +265,23 @@ func (vpn *OutlineVPN) GetTransferMetrics() (BytesTransferred, error) {
request.SetRequestURI(fmt.Sprintf("%s/metrics/transfer", vpn.apiURL))
// Executing request
if err := vpn.session.DoTimeout(request, response, defaultTimeout); err != nil {
return result, err
return &result, err
}

// If data is gathered, status code always must be lower than 400
if response.StatusCode() >= fasthttp.StatusBadRequest {
return result, errors.New("unable to get metrics for keys")
return &result, errors.New("unable to get metrics for keys")
}

// Trying to unmarshal response body as `BytesTransferred`
if err := json.Unmarshal(response.Body(), &result); err != nil {
return result, err
return &result, err
}

return result, nil
return &result, nil
}

func (vpn *OutlineVPN) GetServerInfo() (ServerInfo, error) {
func (vpn *OutlineVPN) GetServerInfo() (*ServerInfo, error) {
request := fasthttp.AcquireRequest()
response := fasthttp.AcquireResponse()
defer fasthttp.ReleaseRequest(request)
Expand All @@ -289,18 +293,53 @@ func (vpn *OutlineVPN) GetServerInfo() (ServerInfo, error) {
request.SetRequestURI(fmt.Sprintf("%s/server", vpn.apiURL))
// Executing request
if err := vpn.session.DoTimeout(request, response, defaultTimeout); err != nil {
return result, err
return &result, err
}

// If data is gathered, status code always must be lower than 400
if response.StatusCode() >= fasthttp.StatusBadRequest {
return result, errors.New("unable to get metrics for keys")
return &result, errors.New("unable to get metrics for keys")
}

// Trying to unmarshal response body as `ServerInfo`
if err := json.Unmarshal(response.Body(), &result); err != nil {
return result, err
return &result, err
}

return result, nil
return &result, nil
}

func (key *OutlineKey) AsSource() (*OutlineConnectionSource, error) {
if key.AccessURL == "" {
return nil, errors.New("unable to retrieve key's access url")
}

// Parse the access url
u, err := url.Parse(key.AccessURL)
if err != nil {
return nil, err
}

// Decode user info
userInfo := strings.TrimPrefix(u.User.String(), ":")
decoded, err := base64.StdEncoding.DecodeString(userInfo)
if err != nil {
return nil, err
}

// Define the host
host := u.Hostname()
// Trying to convert the port into an integer
port, err := strconv.Atoi(u.Port())
if err != nil {
return nil, err
}

// Split decoded data
data := strings.Split(string(decoded), ":")
if len(data) != 2 {
return nil, errors.New("decoded access url doesn't contains password or method")
}

return NewOutlineConnection(host, port, data[1], data[0]), nil
}

0 comments on commit 726dd2b

Please sign in to comment.