upleb.uk

Public git repos — served from a NIP-34 GRASP relay at git.upleb.uk

summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorgreenart7c3 <greenart7c3@proton.me>2023-11-08 10:22:43 -0300
committergreenart7c3 <greenart7c3@proton.me>2023-11-08 10:22:43 -0300
commit86e44b75eb166b600affdc5248e0fe246a6ebe9b (patch)
tree22bc434e074f782ef5315ba6313999e1733b92b2
parentd85f9269ca300fb3bee627733c8086df4fcff875 (diff)
Android Signer Application nip
-rw-r--r--100.md495
1 files changed, 495 insertions, 0 deletions
diff --git a/100.md b/100.md
new file mode 100644
index 0000000..3b8bc8e
--- /dev/null
+++ b/100.md
@@ -0,0 +1,495 @@
1# NIP-100
2
3## Android Signer Application
4
5`draft` `optional` `author:greenart7c3`
6
7This 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.
8
9# Usage for Android applications
10
11The Android signer uses Intents and Content Resolvers to communicate between applications.
12
13To be able to use The Android signer in your application you should add the package name of the signer to your AndroidManifest.xml:
14
15```xml
16<queries>
17 <package android:name="com.example.signer"/>
18</queries>
19```
20
21## Using Intents
22
23To 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.
24
25Create the Intent using the **nostrsigner** scheme:
26
27```kotlin
28val intent = Intent(Intent.ACTION_VIEW, Uri.parse("nostrsigner:$content"))
29```
30
31* Set the Signer package name
32
33```kotlin
34intent.`package` = "com.example.signer"
35```
36
37### Methods
38
39- **get_public_key**
40 - params:
41
42 ```kotlin
43 val intent = Intent(Intent.ACTION_VIEW, Uri.parse("nostrsigner:"))
44 intent.`package` = "com.example.signer"
45 intent.putExtra("type", "get_public_key")
46 context.startActivity(intent)
47 ```
48 - result:
49 - If the user approved intent it will return the **npub** in the signature field
50
51 ```kotlin
52 val npub = intent.data?.getStringExtra("signature")
53 ```
54
55- **sign_event**
56 - params:
57
58 ```kotlin
59 val intent = Intent(Intent.ACTION_VIEW, Uri.parse("nostrsigner:$eventJson"))
60 intent.`package` = "com.example.signer"
61 intent.putExtra("type", "sign_event")
62 // to control the result in your application in case you are not waiting the result before sending another intent
63 intent.putExtra("id", event.id)
64 // Send the current logged in user npub
65 intent.putExtra("current_user", account.keyPair.pubKey.toNpub())
66
67 context.startActivity(intent)
68 ```
69 - result:
70 - If the user approved intent it will return the **signature**, **id** and **event** fields
71
72 ```kotlin
73 val signature = intent.data?.getStringExtra("signature")
74 // the id you sent
75 val id = intent.data?.getStringExtra("id")
76 val signedEventJson = intent.data?.getStringExtra("event")
77 ```
78
79- **nip04_encrypt**
80 - params:
81
82 ```kotlin
83 val intent = Intent(Intent.ACTION_VIEW, Uri.parse("nostrsigner:$plaintext"))
84 intent.`package` = "com.example.signer"
85 intent.putExtra("type", "nip04_encrypt")
86 // to control the result in your application in case you are not waiting the result before sending another intent
87 intent.putExtra("id", "some_id")
88 // Send the current logged in user npub
89 intent.putExtra("current_user", account.keyPair.pubKey.toNpub())
90 // Send the hex pubKey that will be used for encrypting the data
91 intent.putExtra("pubKey", pubKey)
92
93 context.startActivity(intent)
94 ```
95 - result:
96 - If the user approved intent it will return the **signature** and **id** fields
97
98 ```kotlin
99 val encryptedText = intent.data?.getStringExtra("signature")
100 // the id you sent
101 val id = intent.data?.getStringExtra("id")
102 ```
103
104- **nip44_encrypt**
105 - params:
106
107 ```kotlin
108 val intent = Intent(Intent.ACTION_VIEW, Uri.parse("nostrsigner:$plaintext"))
109 intent.`package` = "com.example.signer"
110 intent.putExtra("type", "nip44_encrypt")
111 // to control the result in your application in case you are not waiting the result before sending another intent
112 intent.putExtra("id", "some_id")
113 // Send the current logged in user npub
114 intent.putExtra("current_user", account.keyPair.pubKey.toNpub())
115 // Send the hex pubKey that will be used for encrypting the data
116 intent.putExtra("pubKey", pubKey)
117
118 context.startActivity(intent)
119 ```
120 - result:
121 - If the user approved intent it will return the **signature** and **id** fields
122
123 ```kotlin
124 val encryptedText = intent.data?.getStringExtra("signature")
125 // the id you sent
126 val id = intent.data?.getStringExtra("id")
127 ```
128
129- **nip04_decrypt**
130 - params:
131
132 ```kotlin
133 val intent = Intent(Intent.ACTION_VIEW, Uri.parse("nostrsigner:$encryptedText"))
134 intent.`package` = "com.example.signer"
135 intent.putExtra("type", "nip04_decrypt")
136 // to control the result in your application in case you are not waiting the result before sending another intent
137 intent.putExtra("id", "some_id")
138 // Send the current logged in user npub
139 intent.putExtra("current_user", account.keyPair.pubKey.toNpub())
140 // Send the hex pubKey that will be used for decrypting the data
141 intent.putExtra("pubKey", pubKey)
142
143 context.startActivity(intent)
144 ```
145 - result:
146 - If the user approved intent it will return the **signature** and **id** fields
147
148 ```kotlin
149 val plainText = intent.data?.getStringExtra("signature")
150 // the id you sent
151 val id = intent.data?.getStringExtra("id")
152 ```
153
154- **nip44_decrypt**
155 - params:
156
157 ```kotlin
158 val intent = Intent(Intent.ACTION_VIEW, Uri.parse("nostrsigner:$encryptedText"))
159 intent.`package` = "com.example.signer"
160 intent.putExtra("type", "nip04_decrypt")
161 // to control the result in your application in case you are not waiting the result before sending another intent
162 intent.putExtra("id", "some_id")
163 // Send the current logged in user npub
164 intent.putExtra("current_user", account.keyPair.pubKey.toNpub())
165 // Send the hex pubKey that will be used for decrypting the data
166 intent.putExtra("pubKey", pubKey)
167
168 context.startActivity(intent)
169 ```
170 - result:
171 - If the user approved intent it will return the **signature** and **id** fields
172
173 ```kotlin
174 val plainText = intent.data?.getStringExtra("signature")
175 // the id you sent
176 val id = intent.data?.getStringExtra("id")
177 ```
178
179- **decrypt_zap_event**
180 - params:
181
182 ```kotlin
183 val intent = Intent(Intent.ACTION_VIEW, Uri.parse("nostrsigner:$eventJson"))
184 intent.`package` = "com.example.signer"
185 intent.putExtra("type", "decrypt_zap_event")
186 // to control the result in your application in case you are not waiting the result before sending another intent
187 intent.putExtra("id", "some_id")
188 // Send the current logged in user npub
189 intent.putExtra("current_user", account.keyPair.pubKey.toNpub())
190 context.startActivity(intent)
191 ```
192 - result:
193 - If the user approved intent it will return the **signature** and **id** fields
194
195 ```kotlin
196 val eventJson = intent.data?.getStringExtra("signature")
197 // the id you sent
198 val id = intent.data?.getStringExtra("id")
199 ```
200
201## Using Content Resolver
202
203To 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.
204
205If 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
206
207For the SIGN_EVENT type Signer Application returns two columns "signature" and "event". The column event is the signed event json
208
209For the other types Signer Application returns the column "signature"
210
211### Methods
212
213- **get_public_key**
214 - params:
215
216 ```kotlin
217 val result = context.contentResolver.query(
218 Uri.parse("content://com.example.signer.GET_PUBLIC_KEY"),
219 listOf("login"),
220 null,
221 null,
222 null
223 )
224 ```
225 - result:
226 - Will return the **npub** in the signature column
227
228 ```kotlin
229 if (result == null) return
230
231 if (result.moveToFirst()) {
232 val index = it.getColumnIndex("signature")
233 if (index < 0) return
234 val npub = it.getString(index)
235 }
236 ```
237
238- **sign_event**
239 - params:
240
241 ```kotlin
242 val result = context.contentResolver.query(
243 Uri.parse("content://com.example.signer.SIGN_EVENT"),
244 listOf("$eventJson", "", "${logged_in_user_npub}"),
245 null,
246 null,
247 null
248 )
249 ```
250 - result:
251 - Will return the **signature** and the **event** columns
252
253 ```kotlin
254 if (result == null) return
255
256 if (result.moveToFirst()) {
257 val index = it.getColumnIndex("signature")
258 val indexJson = it.getColumnIndex("event")
259 val signature = it.getString(index)
260 val eventJson = it.getString(indexJson)
261 }
262 ```
263
264- **nip04_encrypt**
265 - params:
266
267 ```kotlin
268 val result = context.contentResolver.query(
269 Uri.parse("content://com.example.signer.NIP04_ENCRYPT"),
270 listOf("$plainText", "${hex_pub_key}", "${logged_in_user_npub}"),
271 null,
272 null,
273 null
274 )
275 ```
276 - result:
277 - Will return the **signature** column
278
279 ```kotlin
280 if (result == null) return
281
282 if (result.moveToFirst()) {
283 val index = it.getColumnIndex("signature")
284 val encryptedText = it.getString(index)
285 }
286 ```
287
288- **nip44_encrypt**
289 - params:
290
291 ```kotlin
292 val result = context.contentResolver.query(
293 Uri.parse("content://com.example.signer.NIP44_ENCRYPT"),
294 listOf("$plainText", "${hex_pub_key}", "${logged_in_user_npub}"),
295 null,
296 null,
297 null
298 )
299 ```
300 - result:
301 - Will return the **signature** column
302
303 ```kotlin
304 if (result == null) return
305
306 if (result.moveToFirst()) {
307 val index = it.getColumnIndex("signature")
308 val encryptedText = it.getString(index)
309 }
310 ```
311
312- **nip04_decrypt**
313 - params:
314
315 ```kotlin
316 val result = context.contentResolver.query(
317 Uri.parse("content://com.example.signer.NIP04_DECRYPT"),
318 listOf("$encryptedText", "${hex_pub_key}", "${logged_in_user_npub}"),
319 null,
320 null,
321 null
322 )
323 ```
324 - result:
325 - Will return the **signature** column
326
327 ```kotlin
328 if (result == null) return
329
330 if (result.moveToFirst()) {
331 val index = it.getColumnIndex("signature")
332 val encryptedText = it.getString(index)
333 }
334 ```
335
336- **nip44_decrypt**
337 - params:
338
339 ```kotlin
340 val result = context.contentResolver.query(
341 Uri.parse("content://com.example.signer.NIP44_DECRYPT"),
342 listOf("$encryptedText", "${hex_pub_key}", "${logged_in_user_npub}"),
343 null,
344 null,
345 null
346 )
347 ```
348 - result:
349 - Will return the **signature** column
350
351 ```kotlin
352 if (result == null) return
353
354 if (result.moveToFirst()) {
355 val index = it.getColumnIndex("signature")
356 val encryptedText = it.getString(index)
357 }
358 ```
359
360- **decrypt_zap_event**
361 - params:
362
363 ```kotlin
364 val result = context.contentResolver.query(
365 Uri.parse("content://com.example.signer.DECRYPT_ZAP_EVENT"),
366 listOf("$eventJson", "", "${logged_in_user_npub}"),
367 null,
368 null,
369 null
370 )
371 ```
372 - result:
373 - Will return the **signature** column
374
375 ```kotlin
376 if (result == null) return
377
378 if (result.moveToFirst()) {
379 val index = it.getColumnIndex("signature")
380 val eventJson = it.getString(index)
381 }
382 ```
383
384# Usage for Web Applications
385
386Since 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.
387
388If you send the callback url parameter Signer Application will send the result to the url.
389
390If you don't send a callback url Signer Application will copy the result to the clipboard.
391
392You can configure the returnType to be **signature** or **event**.
393
394Android 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
395
396## Methods
397
398- **get_public_key**
399 - params:
400
401 ```js
402 const intent = `intent:#Intent;scheme=nostrsigner;S.compressionType=none;S.returnType=signature;S.type=get_public_key;S.callbackUrl=https://example.com/?event=;end`;
403
404 window.href = intent;
405 ```
406
407- **sign_event**
408 - params:
409
410 ```js
411 const intent = `intent:${eventJson}#Intent;scheme=nostrsigner;S.compressionType=none;S.returnType=signature;S.type=sign_event;S.callbackUrl=https://example.com/?event=;end`;
412
413 window.href = intent;
414 ```
415
416- **nip04_encrypt**
417 - params:
418
419 ```js
420 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`;
421
422 window.href = intent;
423 ```
424
425- **nip44_encrypt**
426 - params:
427
428 ```js
429 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`;
430
431 window.href = intent;
432 ```
433
434- **nip04_decrypt**
435 - params:
436
437 ```js
438 const intent = `intent:${encryptedText}#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`;
439
440 window.href = intent;
441 ```
442
443- **nip44_decrypt**
444 - params:
445
446 ```js
447 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`;
448
449 window.href = intent;
450 ```
451
452- **decrypt_zap_event**
453 - params:
454
455 ```js
456 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`;
457
458 window.href = intent;
459 ```
460
461## Example
462
463```js
464<!DOCTYPE html>
465<html lang="en">
466<head>
467 <meta charset="UTF-8">
468 <meta name="viewport" content="width=device-width, initial-scale=1.0">
469 <title>Document</title>
470</head>
471<body>
472 <h1>Test</h1>
473
474 <script>
475 window.onload = function() {
476 var url = new URL(window.location.href);
477 var params = url.searchParams;
478 if (params) {
479 var param1 = params.get("event");
480 if (param1) alert(param1)
481 }
482 let json = {
483 kind: 1,
484 content: "test"
485 }
486 let encodedJson = encodeURIComponent(JSON.stringify(json))
487 var newAnchor = document.createElement("a");
488 newAnchor.href = `intent:${encodedJson}#Intent;scheme=nostrsigner;S.compressionType=none;S.returnType=signature;S.type=sign_event;S.callbackUrl=https://example.com/?event=;end`;
489 newAnchor.textContent = "Open External Signer";
490 document.body.appendChild(newAnchor)
491 }
492 </script>
493</body>
494</html>
495``` \ No newline at end of file