android: add INIT_WITH_AUTHKEY intent

e.g.
adb shell am broadcast  -n com.tailscale.ipn/.IPNReceiver -a com.tailscale.ipn.INIT_WITH_AUTHKEY --es authkey "my-super-secret-authkey"

Signed-off-by: Brad Fitzpatrick <bradfitz@tailscale.com>
bradfitz/authkey_intent
Brad Fitzpatrick 1 year ago
parent 6348bb254a
commit 33d7ad86a6
No known key found for this signature in database

@ -60,6 +60,7 @@
<intent-filter> <intent-filter>
<action android:name="com.tailscale.ipn.CONNECT_VPN" /> <action android:name="com.tailscale.ipn.CONNECT_VPN" />
<action android:name="com.tailscale.ipn.DISCONNECT_VPN" /> <action android:name="com.tailscale.ipn.DISCONNECT_VPN" />
<action android:name="com.tailscale.ipn.INIT_WITH_AUTHKEY" />
</intent-filter> </intent-filter>
</receiver> </receiver>
<service android:name=".IPNService" <service android:name=".IPNService"

@ -9,6 +9,7 @@ import android.content.Context;
import android.content.Intent; import android.content.Intent;
import androidx.work.WorkManager; import androidx.work.WorkManager;
import androidx.work.OneTimeWorkRequest; import androidx.work.OneTimeWorkRequest;
import android.util.Log;
public class IPNReceiver extends BroadcastReceiver { public class IPNReceiver extends BroadcastReceiver {
@ -21,6 +22,9 @@ public class IPNReceiver extends BroadcastReceiver {
workManager.enqueue(new OneTimeWorkRequest.Builder(StartVPNWorker.class).build()); workManager.enqueue(new OneTimeWorkRequest.Builder(StartVPNWorker.class).build());
} else if (intent.getAction() == "com.tailscale.ipn.DISCONNECT_VPN") { } else if (intent.getAction() == "com.tailscale.ipn.DISCONNECT_VPN") {
workManager.enqueue(new OneTimeWorkRequest.Builder(StopVPNWorker.class).build()); workManager.enqueue(new OneTimeWorkRequest.Builder(StopVPNWorker.class).build());
} else if (intent.getAction() == "com.tailscale.ipn.INIT_WITH_AUTHKEY") {
String key = intent.getStringExtra("authkey");
IPNService.setAuthKeyForNextConnect(key);
} }
} }
} }

@ -119,6 +119,8 @@ public class IPNService extends VpnService {
startForeground(App.STATUS_NOTIFICATION_ID, builder.build()); startForeground(App.STATUS_NOTIFICATION_ID, builder.build());
} }
public static native void setAuthKeyForNextConnect(String authKey);
private native void connect(); private native void connect();
private native void disconnect(); private native void disconnect();

@ -33,6 +33,9 @@ var (
// onConnectivityChange is notified every time the network // onConnectivityChange is notified every time the network
// conditions change. // conditions change.
onConnectivityChange = make(chan bool, 1) onConnectivityChange = make(chan bool, 1)
// onSetAuthKeyForNextConnect gets an authkey for use in the next connect
// when IPNReceiver receives one.
onSetAuthKeyForNextConnect = make(chan string, 1)
// onGoogleToken receives google ID tokens. // onGoogleToken receives google ID tokens.
onGoogleToken = make(chan string) onGoogleToken = make(chan string)
@ -109,12 +112,12 @@ func Java_com_tailscale_ipn_IPNService_disconnect(env *C.JNIEnv, this C.jobject)
//export Java_com_tailscale_ipn_StartVPNWorker_connect //export Java_com_tailscale_ipn_StartVPNWorker_connect
func Java_com_tailscale_ipn_StartVPNWorker_connect(env *C.JNIEnv, this C.jobject) { func Java_com_tailscale_ipn_StartVPNWorker_connect(env *C.JNIEnv, this C.jobject) {
requestBackend(ConnectEvent{Enable: true}) requestBackend(ConnectEvent{Enable: true})
} }
//export Java_com_tailscale_ipn_StopVPNWorker_disconnect //export Java_com_tailscale_ipn_StopVPNWorker_disconnect
func Java_com_tailscale_ipn_StopVPNWorker_disconnect(env *C.JNIEnv, this C.jobject) { func Java_com_tailscale_ipn_StopVPNWorker_disconnect(env *C.JNIEnv, this C.jobject) {
requestBackend(ConnectEvent{Enable: false}) requestBackend(ConnectEvent{Enable: false})
} }
//export Java_com_tailscale_ipn_App_onConnectivityChanged //export Java_com_tailscale_ipn_App_onConnectivityChanged
@ -200,3 +203,13 @@ func Java_com_tailscale_ipn_App_onShareIntent(env *C.JNIEnv, cls C.jclass, nfile
} }
onFileShare <- files onFileShare <- files
} }
//export Java_com_tailscale_ipn_IPNService_setAuthKeyForNextConnect
func Java_com_tailscale_ipn_IPNService_setAuthKeyForNextConnect(env *C.JNIEnv, this C.jobject, authKeyJStr C.jobject) {
jenv := (*jni.Env)(unsafe.Pointer(env))
authKey := jni.GoString(jenv, jni.String(authKeyJStr))
select {
case onSetAuthKeyForNextConnect <- authKey:
default:
}
}

@ -164,6 +164,9 @@ type ConnectEvent struct {
Enable bool Enable bool
} }
type SetAuthKeyEvent struct {
AuthKey string
}
type CopyEvent struct { type CopyEvent struct {
Text string Text string
} }
@ -441,6 +444,27 @@ func (a *App) runBackend() error {
go b.backend.StartLoginInteractive() go b.backend.StartLoginInteractive()
signingIn = true signingIn = true
} }
case SetAuthKeyEvent:
authKey := e.AuthKey
if b.backend.State() <= ipn.Stopped {
log.Printf("using authkey; state=%v", b.backend.State())
go func() {
prefs := ipn.NewPrefs()
prefs.WantRunning = true
err := b.backend.Start(ipn.Options{
AuthKey: authKey,
UpdatePrefs: prefs,
})
log.Printf("authkey: Start error = %v", err)
if err != nil {
fatalErr(err)
} else {
b.backend.StartLoginInteractive()
}
}()
} else {
log.Printf("ignoring authkey in state=%v", b.backend.State())
}
case SetLoginServerEvent: case SetLoginServerEvent:
state.Prefs.ControlURL = e.URL state.Prefs.ControlURL = e.URL
b.backend.SetPrefs(state.Prefs) b.backend.SetPrefs(state.Prefs)
@ -895,6 +919,9 @@ func (a *App) runUI() error {
w.Invalidate() w.Invalidate()
} }
} }
case authKey := <-onSetAuthKeyForNextConnect:
ui.ShowMessage("got authkey")
requestBackend(SetAuthKeyEvent{AuthKey: authKey})
case p := <-a.prefs: case p := <-a.prefs:
ui.enabled.Value = p.WantRunning ui.enabled.Value = p.WantRunning
ui.runningExit = p.AdvertisesExitNode() ui.runningExit = p.AdvertisesExitNode()

Loading…
Cancel
Save