Keychain 6.0.4 no longer exports the legacy org.openintents.openpgp.api.OpenPgpService action, so the OpenPgpServiceConnection from openpgp-api.jar bound nothing and every encrypt/decrypt died with a NullPointerException in OpenPgpApi.executeApi. Bind our own ServiceConnection against org.openintents.openpgp.IOpenPgpService (falling back to the legacy action for older Keychain releases), and queue API calls until the service is actually connected instead of racing the async bind. Also fix the //go:generate recipe: it built one jar containing both PgpConnect and Permissions, which collides with Permissions.jar when gogio dexes every *.jar in the repo root.
116 lines
2.8 KiB
Go
116 lines
2.8 KiB
Go
//go:build android
|
|
// +build android
|
|
|
|
// Regenerate PgpConnect.jar and Permissions.jar (gogio dexes every *.jar in
|
|
// the repo root; the two classes must stay in separate jars). ANDROID_HOME
|
|
// must be set. Note: go generate skips this file on non-android hosts.
|
|
//go:generate sh -c 'mkdir -p classes && javac -nowarn -classpath "$ANDROID_HOME/platforms/android-35/android.jar:openpgp-api.jar" -d classes PgpConnect.java Permissions.java && (cd classes && jar cf ../../PgpConnect.jar st/wow/git/passgo/PgpConnect* && jar cf ../../Permissions.jar st/wow/git/passgo/Permissions*) && rm -rf classes'
|
|
|
|
package passgo
|
|
|
|
/*
|
|
#import <jni.h>
|
|
#import "jni_android.h"
|
|
*/
|
|
import "C"
|
|
|
|
import (
|
|
"fmt"
|
|
"io/ioutil"
|
|
"log"
|
|
"path"
|
|
"strings"
|
|
"sync"
|
|
"unsafe"
|
|
|
|
"gioui.org/app"
|
|
_ "gioui.org/app/permission/storage"
|
|
//"git.wow.st/gmp/jni"
|
|
)
|
|
|
|
var (
|
|
jvm uintptr
|
|
waitch chan struct{}
|
|
//w *app.Window
|
|
pgp PGP
|
|
installCompleteOnce sync.Once
|
|
)
|
|
|
|
func init() {
|
|
waitch = make(chan struct{})
|
|
}
|
|
|
|
//export Java_st_wow_git_passgo_PgpConnect_installComplete
|
|
func Java_st_wow_git_passgo_PgpConnect_installComplete(env *C.JNIEnv, class C.jclass, p C.jobject) {
|
|
log.Printf("InstallComplete()")
|
|
pgp = PGP(C.NewGlobalRef(env, p))
|
|
installCompleteOnce.Do(func() {
|
|
close(waitch)
|
|
})
|
|
}
|
|
|
|
func InitPgp(view uintptr) {
|
|
log.Printf("InitPgp()")
|
|
if view == 0 {
|
|
return // detach signal; nothing to register
|
|
}
|
|
jvm = app.JavaVM()
|
|
SetJVM(jvm) // why?
|
|
RunInJVM(func(env *JNIEnv) {
|
|
C.registerFragment(env, (C.jobject)(unsafe.Pointer(view)))
|
|
})
|
|
}
|
|
|
|
// InitPermissions registers the Permissions fragment, which requests the
|
|
// storage permissions (launching the system "All files access" settings
|
|
// screen on Android 11+) so the app can read the store in shared storage.
|
|
func InitPermissions(view uintptr) {
|
|
log.Printf("InitPermissions()")
|
|
if view == 0 {
|
|
return // detach signal; nothing to register
|
|
}
|
|
RunInJVM(func(env *JNIEnv) {
|
|
C.registerPermissionsFragment(env, (C.jobject)(unsafe.Pointer(view)))
|
|
})
|
|
}
|
|
|
|
func stopPgp() {
|
|
waitch = make(chan struct{})
|
|
}
|
|
|
|
func connect() {
|
|
<-waitch
|
|
}
|
|
|
|
// Clip copies a string to the clipboard
|
|
func Clip(x string) {
|
|
pgp.Clip(x)
|
|
}
|
|
|
|
func (s *Store) nativeDecrypt(name string) (string, error) {
|
|
connect()
|
|
data, err := ioutil.ReadFile(path.Join(s.Dir, strings.Join([]string{name, ".gpg"}, "")))
|
|
if err != nil {
|
|
return "", fmt.Errorf("Error reading file: %s", err)
|
|
}
|
|
ret, err := pgp.Decrypt(string(data))
|
|
return ret, err
|
|
}
|
|
|
|
func (s *Store) nativeEncrypt(pw string) ([]byte, error) {
|
|
connect()
|
|
ret, err := pgp.Encrypt(s.Id, pw)
|
|
return []byte(ret), err
|
|
}
|
|
|
|
func nativeIdentities() ([]string, error) {
|
|
//NOT IMPLEMENTED ON ANDROID
|
|
return []string{}, nil
|
|
log.Printf("nativeIdentities()")
|
|
connect()
|
|
log.Printf("calling pgp.GetId()")
|
|
id, err := pgp.GetId()
|
|
log.Printf("pgp.GetId() returned")
|
|
return []string{id}, err
|
|
}
|