Skip to content
Snippets Groups Projects
api.go 6.08 KiB
Newer Older
  • Learn to ignore specific revisions
  • /* All the exported functions should be added here */
    
    
    package backend
    
    import (
    	"C"
    
    	"encoding/json"
    
    Kali Kaneko's avatar
    Kali Kaneko committed
    	"os"
    
    	"strings"
    
    	"unsafe"
    
    	"0xacab.org/leap/bitmask-vpn/pkg/bitmask"
    
    	"0xacab.org/leap/bitmask-vpn/pkg/config/version"
    
    	"0xacab.org/leap/bitmask-vpn/pkg/pickle"
    
    	"0xacab.org/leap/bitmask-vpn/pkg/pid"
    
    	"github.com/rs/zerolog/log"
    
    func Login(username, password string) {
    	success, err := ctx.bm.DoLogin(username, password)
    	if err != nil {
    
    		log.Warn().
    			Err(err).
    			Str("username", username).
    			Msg("Could not log in")
    
    		if err.Error() == "TokenErrTimeout" {
    			ctx.Errors = "bad_auth_timeout"
    		} else if err.Error() == "TokenErrBadStatus 502" {
    
    			ctx.Errors = "bad_auth_502"
    		} else {
    			ctx.Errors = "bad_auth"
    		}
    
    	} else if success {
    
    		log.Info().
    			Str("username", username).
    			Msg("Sucessfully logged in")
    
    Kali Kaneko's avatar
    Kali Kaneko committed
    		ctx.LoginOk = true
    		ctx.LoginDialog = false
    
    		log.Warn().
    			Str("username", username).
    			Msg("Could not log in (else)")
    
    		ctx.LoginDialog = true
    
    Kali Kaneko's avatar
    Kali Kaneko committed
    		ctx.Errors = "bad_auth"
    
    	// XXX shouldn't this be statusChanged?
    
    Kali Kaneko's avatar
    Kali Kaneko committed
    	go ctx.updateStatus()
    
    func setError(err string) {
    	ctx.Errors = err
    	go setStatus(off)
    	go ctx.updateStatus()
    }
    
    
    func SwitchOn() {
    	go setStatus(starting)
    	go startVPN()
    }
    
    func SwitchOff() {
    	go setStatus(stopping)
    	go stopVPN()
    }
    
    
    func UseLocation(label string) {
    
    	if ctx.ManualLocation && label == ctx.CurrentLocation {
    		return
    	}
    
    
    	ctx.bm.UseGateway(label)
    
    	go trigger(OnStatusChanged)
    
    	if ctx.Status == on && label != strings.ToLower(ctx.CurrentLocation) {
    
    		go ctx.bm.Reconnect()
    
    	}
    }
    
    func UseAutomaticGateway() {
    	if !ctx.ManualLocation {
    		return
    	}
    
    	ctx.bm.UseAutomaticGateway()
    	go trigger(OnStatusChanged)
    
    	if ctx.Status == on {
    		ctx.bm.Reconnect()
    	}
    
    func SetTransport(label string) {
    
    	err := ctx.bm.SetTransport(label)
    	if err != nil {
    
    		log.Warn().
    			Err(err).
    			Str("transport", label).
    			Msg("Could not set transport")
    
    	}
    	if label == "obfs4" {
    
    		// XXX this is an expedite way of avoiding the corner case
    		// in which user has selected a manual location that does not offer bridges.
    		// In the future, we can be more delicate and 1. do the switch only if the manual location
    		// is incompatible with obfs4; 2. notify the user of the change.
    		// But tonight we're in problem-solving mode, and we can assume that user wants to use bridges,
    		// no matter what. So let's assume that "use obfs4" supersedes everything else and be done.
    		UseAutomaticGateway()
    
    		ctx.cfg.SetUseObfs4(true)
    	} else {
    		ctx.cfg.SetUseObfs4(false)
    	}
    	go trigger(OnStatusChanged)
    }
    
    func SetUDP(udp bool) {
    
    	log.Info().
    		Bool("useUDP", udp).
    		Msg("Configuring UDP")
    
    	ctx.cfg.SetUseUDP(udp)
    
    	ctx.bm.UseUDP(udp)
    
    	go trigger(OnStatusChanged)
    
    func SetSnowflake(snowflake bool) {
    
    	log.Info().
    		Bool("useSnowflake", snowflake).
    		Msg("Configuring Snowflake")
    
    	ctx.cfg.SetUseSnowflake(snowflake)
    	ctx.bm.UseSnowflake(snowflake)
    	go trigger(OnStatusChanged)
    }
    
    
    func GetTransport() *C.char {
    	return C.CString(ctx.bm.GetTransport())
    }
    
    
    	if ctx.autostart != nil {
    
    		err := ctx.autostart.Disable()
    		if err != nil {
    			log.Warn().
    				Err(err).
    				Msg("Could not disable autostart")
    		}
    
    	if ctx.Status != off {
    		go setStatus(stopping)
    
    		err := ctx.cfg.SetUserStoppedVPN(false)
    		if err != nil {
    			log.Warn().
    				Err(err).
    				Bool("userStopped", false).
    				Msg("Could not set UserStoppedVPN")
    		}
    
    		err := ctx.cfg.SetUserStoppedVPN(true)
    		if err != nil {
    			log.Warn().
    				Err(err).
    				Bool("userStopped", false).
    				Msg("Could not set UserStoppedVPN")
    		}
    
    	if ctx.bm != nil {
    		ctx.bm.Close()
    	}
    
    	err := pid.ReleasePID()
    	if err != nil {
    		log.Warn().
    			Err(err).
    			Msg("Could not release PID")
    	}
    
    func DonateAccepted() {
    	donateAccepted()
    }
    
    
    func DonateSeen() {
    	donateSeen()
    }
    
    
    func SubscribeToEvent(event string, f unsafe.Pointer) {
    	subscribe(event, f)
    }
    
    
    type Providers struct {
    
    	Default string                 `json:"default"`
    	Data    []bitmask.ProviderOpts `json:"providers"`
    
    Kali Kaneko's avatar
    Kali Kaneko committed
    type InitOpts struct {
    
    	ProviderOptions  *bitmask.ProviderOpts
    	SkipLaunch       bool
    	Obfs4            bool
    
    	DisableAutostart bool
    	StartVPN         string
    
    }
    
    func InitOptsFromJSON(provider, providersJSON string) *InitOpts {
    
    	providers := Providers{}
    	err := json.Unmarshal([]byte(providersJSON), &providers)
    
    	if err != nil {
    
    		log.Fatal().
    			Err(err).
    			Str("providersJson", providersJSON).
    			Msg("Could not parse provider json")
    
    Kali Kaneko's avatar
    Kali Kaneko committed
    	var providerOpts *bitmask.ProviderOpts
    	providerOpts = &providers.Data[0]
    
    	if len(providers.Data) != 1 {
    
    Kali Kaneko's avatar
    Kali Kaneko committed
    		chosenProvider := os.Getenv("LEAP_PROVIDER")
    		if chosenProvider != "" {
    			for _, p := range providers.Data {
    				if p.Provider == chosenProvider {
    
    					log.Info().
    						Str("provider", chosenProvider).
    						Msg("Selecting provider")
    
    Kali Kaneko's avatar
    Kali Kaneko committed
    					return &InitOpts{ProviderOptions: &p}
    				}
    			}
    
    			log.Fatal().
    				Str("provider", chosenProvider).
    				Msg("Provider not found in providers.json")
    
    	return &InitOpts{ProviderOptions: providerOpts}
    
    Kali Kaneko's avatar
    Kali Kaneko committed
    }
    
    func InitializeBitmaskContext(opts *InitOpts) {
    
    	bitmask.ConfigureProvider(opts.ProviderOptions)
    
    Kali Kaneko's avatar
    Kali Kaneko committed
    	initOnce.Do(func() { initializeContext(opts) })
    
    	if ctx.bm != nil {
    
    		ctx.LoginDialog = ctx.bm.NeedsCredentials()
    
    		go ctx.updateStatus()
    	}
    
    	if ctx.AskForDonations {
    		runDonationReminder()
    	}
    
    }
    
    func RefreshContext() *C.char {
    
    	c, err := ctx.toJson()
    	if err != nil {
    		log.Warn().
    			Err(err).
    			Msg("Could not refresh context")
    	}
    
    	return C.CString(string(c))
    }
    
    
    Kali Kaneko's avatar
    Kali Kaneko committed
    func ResetError(errname string) {
    
    Kali Kaneko's avatar
    Kali Kaneko committed
    	if ctx.Errors == errname {
    		ctx.Errors = ""
    	}
    }
    
    func ResetNotification(label string) {
    	switch label {
    	case "login_ok":
    		ctx.LoginOk = false
    	default:
    		break
    	}
    	go trigger(OnStatusChanged)
    
    func InstallHelpers() {
    	pickle.InstallHelpers()
    }
    
    
    Kali Kaneko's avatar
    Kali Kaneko committed
    func EnableMockBackend() {
    
    	log.Info().Msg("[+] Mocking ui interaction on port 8080. \nTry 'curl localhost:8080/{on|off|failed}' to toggle status.")
    
    Kali Kaneko's avatar
    Kali Kaneko committed
    	go enableMockBackend()
    
    func EnableWebAPI(port string) {
    	intPort, err := strconv.Atoi(port)
    	if err != nil {
    
    		log.Fatal().
    			Err(err).
    			Str("port", port).
    			Msg("Could not parse WebAPI port")
    
    	}
    	go enableWebAPI(intPort)
    
    func GetVersion() *C.char {
    
    	return C.CString(version.Version())