# NIP-100 ## Android Signer Application `draft` `optional` `author:greenart7c3` This NIP describes a method for 2-way communication between a android signer and any Nostr client on Android. The Android signer is an Android Application and the Client can be a Web Client or an Android Application. # Usage for Android applications The Android signer uses Intents and Content Resolvers to communicate between applications. To be able to use The Android signer in your application you should this to your AndroidManifest.xml: ```xml ``` Then you can use this function to check if there's a signer application installed: ```kotlin fun isExternalSignerInstalled(context: Context): Boolean { val intent = Intent().apply { action = Intent.ACTION_VIEW data = Uri.parse("nostrsigner:") } val infos = context.packageManager.queryIntentActivities(intent, 0) return infos.size > 0 } ``` ## Using Intents To get the result back from the Signer Appication you should use registerForActivityResult or rememberLauncherForActivityResult in Kotlin. If you are using another framework check the documentation of your framework or a third party library to get the result. Create the Intent using the **nostrsigner** scheme: ```kotlin val intent = Intent(Intent.ACTION_VIEW, Uri.parse("nostrsigner:$content")) ``` * Set the Signer package name ```kotlin intent.`package` = "com.example.signer" ``` ### Methods - **get_public_key** - params: ```kotlin val intent = Intent(Intent.ACTION_VIEW, Uri.parse("nostrsigner:")) intent.`package` = "com.example.signer" intent.putExtra("type", "get_public_key") // You can send some default permissions for the user authorize for ever val permissions = listOf( Permission( "sign_event", 22242 ), Permission( "nip44_decrypt" ) ) intent.putExtra("permissions", permissions.toJson()) context.startActivity(intent) ``` - result: - If the user approved intent it will return the **npub** in the signature field ```kotlin val npub = intent.data?.getStringExtra("signature") // The package name of the signer application val packageName = intent.data?.getStringExtra("package") ``` - **sign_event** - params: ```kotlin val intent = Intent(Intent.ACTION_VIEW, Uri.parse("nostrsigner:$eventJson")) intent.`package` = "com.example.signer" intent.putExtra("type", "sign_event") // to control the result in your application in case you are not waiting the result before sending another intent intent.putExtra("id", event.id) // Send the current logged in user npub intent.putExtra("current_user", account.keyPair.pubKey.toNpub()) context.startActivity(intent) ``` - result: - If the user approved intent it will return the **signature**, **id** and **event** fields ```kotlin val signature = intent.data?.getStringExtra("signature") // the id you sent val id = intent.data?.getStringExtra("id") val signedEventJson = intent.data?.getStringExtra("event") ``` - **nip04_encrypt** - params: ```kotlin val intent = Intent(Intent.ACTION_VIEW, Uri.parse("nostrsigner:$plaintext")) intent.`package` = "com.example.signer" intent.putExtra("type", "nip04_encrypt") // to control the result in your application in case you are not waiting the result before sending another intent intent.putExtra("id", "some_id") // Send the current logged in user npub intent.putExtra("current_user", account.keyPair.pubKey.toNpub()) // Send the hex pubKey that will be used for encrypting the data intent.putExtra("pubKey", pubKey) context.startActivity(intent) ``` - result: - If the user approved intent it will return the **signature** and **id** fields ```kotlin val encryptedText = intent.data?.getStringExtra("signature") // the id you sent val id = intent.data?.getStringExtra("id") ``` - **nip44_encrypt** - params: ```kotlin val intent = Intent(Intent.ACTION_VIEW, Uri.parse("nostrsigner:$plaintext")) intent.`package` = "com.example.signer" intent.putExtra("type", "nip44_encrypt") // to control the result in your application in case you are not waiting the result before sending another intent intent.putExtra("id", "some_id") // Send the current logged in user npub intent.putExtra("current_user", account.keyPair.pubKey.toNpub()) // Send the hex pubKey that will be used for encrypting the data intent.putExtra("pubKey", pubKey) context.startActivity(intent) ``` - result: - If the user approved intent it will return the **signature** and **id** fields ```kotlin val encryptedText = intent.data?.getStringExtra("signature") // the id you sent val id = intent.data?.getStringExtra("id") ``` - **nip04_decrypt** - params: ```kotlin val intent = Intent(Intent.ACTION_VIEW, Uri.parse("nostrsigner:$encryptedText")) intent.`package` = "com.example.signer" intent.putExtra("type", "nip04_decrypt") // to control the result in your application in case you are not waiting the result before sending another intent intent.putExtra("id", "some_id") // Send the current logged in user npub intent.putExtra("current_user", account.keyPair.pubKey.toNpub()) // Send the hex pubKey that will be used for decrypting the data intent.putExtra("pubKey", pubKey) context.startActivity(intent) ``` - result: - If the user approved intent it will return the **signature** and **id** fields ```kotlin val plainText = intent.data?.getStringExtra("signature") // the id you sent val id = intent.data?.getStringExtra("id") ``` - **nip44_decrypt** - params: ```kotlin val intent = Intent(Intent.ACTION_VIEW, Uri.parse("nostrsigner:$encryptedText")) intent.`package` = "com.example.signer" intent.putExtra("type", "nip04_decrypt") // to control the result in your application in case you are not waiting the result before sending another intent intent.putExtra("id", "some_id") // Send the current logged in user npub intent.putExtra("current_user", account.keyPair.pubKey.toNpub()) // Send the hex pubKey that will be used for decrypting the data intent.putExtra("pubKey", pubKey) context.startActivity(intent) ``` - result: - If the user approved intent it will return the **signature** and **id** fields ```kotlin val plainText = intent.data?.getStringExtra("signature") // the id you sent val id = intent.data?.getStringExtra("id") ``` - **decrypt_zap_event** - params: ```kotlin val intent = Intent(Intent.ACTION_VIEW, Uri.parse("nostrsigner:$eventJson")) intent.`package` = "com.example.signer" intent.putExtra("type", "decrypt_zap_event") // to control the result in your application in case you are not waiting the result before sending another intent intent.putExtra("id", "some_id") // Send the current logged in user npub intent.putExtra("current_user", account.keyPair.pubKey.toNpub()) context.startActivity(intent) ``` - result: - If the user approved intent it will return the **signature** and **id** fields ```kotlin val eventJson = intent.data?.getStringExtra("signature") // the id you sent val id = intent.data?.getStringExtra("id") ``` ## Using Content Resolver To get the result back from Signer Application you should use contentResolver.query in Kotlin. If you are using another framework check the documentation of your framework or a third party library to get the result. If the user did not check the remember my choice option, the npub is not in Signer Application or the signer type is not recognized the contentResolver will return null For the SIGN_EVENT type Signer Application returns two columns "signature" and "event". The column event is the signed event json For the other types Signer Application returns the column "signature" If the user chose to always reject the event signer application will return the column "rejected" and you should not open signer application ### Methods - **get_public_key** - params: ```kotlin val result = context.contentResolver.query( Uri.parse("content://com.example.signer.GET_PUBLIC_KEY"), listOf("login"), null, null, null ) ``` - result: - Will return the **npub** in the signature column ```kotlin if (result == null) return if (result.moveToFirst()) { val index = it.getColumnIndex("signature") if (index < 0) return val npub = it.getString(index) } ``` - **sign_event** - params: ```kotlin val result = context.contentResolver.query( Uri.parse("content://com.example.signer.SIGN_EVENT"), listOf("$eventJson", "", "${logged_in_user_npub}"), null, null, null ) ``` - result: - Will return the **signature** and the **event** columns ```kotlin if (result == null) return if (result.moveToFirst()) { val index = it.getColumnIndex("signature") val indexJson = it.getColumnIndex("event") val signature = it.getString(index) val eventJson = it.getString(indexJson) } ``` - **nip04_encrypt** - params: ```kotlin val result = context.contentResolver.query( Uri.parse("content://com.example.signer.NIP04_ENCRYPT"), listOf("$plainText", "${hex_pub_key}", "${logged_in_user_npub}"), null, null, null ) ``` - result: - Will return the **signature** column ```kotlin if (result == null) return if (result.moveToFirst()) { val index = it.getColumnIndex("signature") val encryptedText = it.getString(index) } ``` - **nip44_encrypt** - params: ```kotlin val result = context.contentResolver.query( Uri.parse("content://com.example.signer.NIP44_ENCRYPT"), listOf("$plainText", "${hex_pub_key}", "${logged_in_user_npub}"), null, null, null ) ``` - result: - Will return the **signature** column ```kotlin if (result == null) return if (result.moveToFirst()) { val index = it.getColumnIndex("signature") val encryptedText = it.getString(index) } ``` - **nip04_decrypt** - params: ```kotlin val result = context.contentResolver.query( Uri.parse("content://com.example.signer.NIP04_DECRYPT"), listOf("$encryptedText", "${hex_pub_key}", "${logged_in_user_npub}"), null, null, null ) ``` - result: - Will return the **signature** column ```kotlin if (result == null) return if (result.moveToFirst()) { val index = it.getColumnIndex("signature") val encryptedText = it.getString(index) } ``` - **nip44_decrypt** - params: ```kotlin val result = context.contentResolver.query( Uri.parse("content://com.example.signer.NIP44_DECRYPT"), listOf("$encryptedText", "${hex_pub_key}", "${logged_in_user_npub}"), null, null, null ) ``` - result: - Will return the **signature** column ```kotlin if (result == null) return if (result.moveToFirst()) { val index = it.getColumnIndex("signature") val encryptedText = it.getString(index) } ``` - **decrypt_zap_event** - params: ```kotlin val result = context.contentResolver.query( Uri.parse("content://com.example.signer.DECRYPT_ZAP_EVENT"), listOf("$eventJson", "", "${logged_in_user_npub}"), null, null, null ) ``` - result: - Will return the **signature** column ```kotlin if (result == null) return if (result.moveToFirst()) { val index = it.getColumnIndex("signature") val eventJson = it.getString(index) } ``` # Usage for Web Applications Since web applications can't receive a result from the intent you should add a modal to paste the signature or the event json or create a callback url. If you send the callback url parameter Signer Application will send the result to the url. If you don't send a callback url Signer Application will copy the result to the clipboard. You can configure the returnType to be **signature** or **event**. Android intents and browsers url has limitations, so if you are using the returnType of **event** consider using the parameter **compressionType=gzip** that will return "Signer1" + Base 64 gzip encoded event json ## Methods - **get_public_key** - params: ```js const intent = `intent:#Intent;scheme=nostrsigner;S.compressionType=none;S.returnType=signature;S.type=get_public_key;S.callbackUrl=https://example.com/?event=;end`; window.href = intent; ``` - **sign_event** - params: ```js const intent = `intent:${eventJson}#Intent;scheme=nostrsigner;S.compressionType=none;S.returnType=signature;S.type=sign_event;S.callbackUrl=https://example.com/?event=;end`; window.href = intent; ``` - **nip04_encrypt** - params: ```js const intent = `intent:${plainText}#Intent;scheme=nostrsigner;S.pubKey=${hex_pub_key};S.compressionType=none;S.returnType=signature;S.type=nip04_encrypt;S.callbackUrl=https://example.com/?event=;end`; window.href = intent; ``` - **nip44_encrypt** - params: ```js const intent = `intent:${plainText}#Intent;scheme=nostrsigner;S.pubKey=${hex_pub_key};S.compressionType=none;S.returnType=signature;S.type=nip44_encrypt;S.callbackUrl=https://example.com/?event=;end`; window.href = intent; ``` - **nip04_decrypt** - params: ```js const intent = `intent:${encryptedText}#Intent;scheme=nostrsigner;S.pubKey=${hex_pub_key};S.compressionType=none;S.returnType=signature;S.type=nip04_decrypt;S.callbackUrl=https://example.com/?event=;end`; window.href = intent; ``` - **nip44_decrypt** - params: ```js const intent = `intent:${encryptedText}#Intent;scheme=nostrsigner;S.pubKey=${hex_pub_key};S.compressionType=none;S.returnType=signature;S.type=nip44_decrypt;S.callbackUrl=https://example.com/?event=;end`; window.href = intent; ``` - **decrypt_zap_event** - params: ```js const intent = `intent:${eventJson}#Intent;scheme=nostrsigner;S.compressionType=none;S.returnType=signature;S.type=decrypt_zap_event;S.callbackUrl=https://example.com/?event=;end`; window.href = intent; ``` ## Example ```js Document

Test

```