Blocto
Search…
Push Notification
Push notification is a powerful tool most mobile web apps are missing. Blocto helps you bridge the gap and helps you push on demand.

Domains

Environment
Domain
Staging
api-staging.blocto.app
Production
api.blocto.app
1
Authorization: <JWT>
2
Content-Type: application/json
Copied!

APIs

post
https://api.blocto.app
/notification/send
Send push notification
get
https://api.blocto.app
/notification/tag
Tag users by user ID

Getting User IDs From your Web App

Blocto injects a global API into websites at window.bloctoProvider and window.{network} at the same time. Currently, Blocto supports networks:
  • ethereum
  • tron
  • tangerine

Register Push Notification

1
let web3 = new Web3(window.ethereum) // or window.tangerine or window.bloctoProvider
2
if (web3.currentProvider.isBlocto) {
3
try {
4
let encryptedUserId = await web3.currentProvider.registerPushNotification("{appId}")
5
// send encryptedUserId to your backend
6
} catch(e) {
7
// error handling
8
// e.mesage: see the below
9
}
10
}
Copied!
Error Handling
  • blocked: user clicked the block button.
  • cancelled: user clicked the cancel button.
  • noNetworkConnection: no network connection.
  • appIdNotExist: your app id doesn't exist.
  • internal: wallet app internal error. Please contact us.
Decrypt User ID
JavaScript
Golang
1
var aesjs = require('aes-js');
2
​
3
// The aes key provided by blocto, and make sure it is stored in somewhere safe.
4
var key = aesjs.utils.hex.toBytes('71500f4803c54fcf9445a09e3434afce7552d9916bce4480e54c48a246be3f05');
5
​
6
// The encrypted data from blocto web3 provider.
7
var ivAndEncryptedData = aesjs.utils.hex.toBytes('3b28cd5be9629b777392e968fef4b0e9ea2715b4f9966ddbfa4dab41b6468a0c30476c6d1e4f58d1b22c9877eaf8bf626dc4f3f10932208684235927b28a2cd85d5aea5595fcd0618019fe80a1afd35c');
8
​
9
var iv = ivAndEncryptedData.slice(0, 16);
10
var encryptedBytes = ivAndEncryptedData.slice(16);
11
​
12
var aesCbc = new aesjs.ModeOfOperation.cbc(key, iv);
13
var paddedDecryptedBytes = aesCbc.decrypt(encryptedBytes);
14
​
15
let res = unpad(paddedDecryptedBytes);
16
if (res.err) {
17
throw res.err
18
}
19
​
20
console.log(JSON.parse(ab2str(res.unpaddedBytes)));
21
// `{ user_id: '79efdb10-64dd-436a-9ec9-6bfda8c36e1d' }` is expected
22
// Store the `user_id` and make some mapping according to your application.
23
​
24
function ab2str(buf) {
25
return String.fromCharCode.apply(null, new Uint16Array(buf));
26
}
27
​
28
function unpad(decryptedBytes) {
29
let paddedLen = decryptedBytes.length;
30
if (paddedLen === 0) {
31
return {
32
unpaddedBytes: null,
33
err: new Error('invalid padding size'),
34
}
35
}
36
​
37
let padLen = decryptedBytes[paddedLen - 1];
38
if (padLen > paddedLen || padLen > 16) {
39
return {
40
unpaddedBytes: null,
41
err: new Error('invalid padding size'),
42
}
43
}
44
​
45
for (let i = paddedLen - padLen; i < decryptedBytes.length; i++) {
46
if (decryptedBytes[i] !== padLen) {
47
return {
48
unpaddedBytes: null,
49
err: new Error('invalid padding'),
50
}
51
}
52
}
53
​
54
return {
55
unpaddedBytes: decryptedBytes.slice(0, paddedLen - padLen),
56
err: null,
57
}
58
}
Copied!
1
package main
2
​
3
import (
4
"crypto/aes"
5
"crypto/cipher"
6
"encoding/hex"
7
"encoding/json"
8
"errors"
9
"fmt"
10
)
11
​
12
func main() {
13
// The aes key provided by blocto, and make sure it is stored in somewhere safe.
14
key, err := hex.DecodeString("71500f4803c54fcf9445a09e3434afce7552d9916bce4480e54c48a246be3f05")
15
if err != nil {
16
panic(err)
17
}
18
​
19
// The encrypted data from blocto web3 provider.
20
encryptedData, err := hex.DecodeString("3b28cd5be9629b777392e968fef4b0e9ea2715b4f9966ddbfa4dab41b6468a0c30476c6d1e4f58d1b22c9877eaf8bf626dc4f3f10932208684235927b28a2cd85d5aea5595fcd0618019fe80a1afd35c")
21
if err != nil {
22
panic(err)
23
}
24
​
25
decryptedData, err := CBCDecrypt(key, encryptedData)
26
if err != nil {
27
panic(err)
28
}
29
​
30
type data struct {
31
UserID string `json:"user_id"`
32
}
33
34
d := &data{}
35
err = json.Unmarshal(decryptedData, d)
36
if err != nil {
37
panic(err)
38
}
39
​
40
fmt.Println(d.UserID)
41
// `79efdb10-64dd-436a-9ec9-6bfda8c36e1d` is expected
42
// Store the `user_id` and make some mapping according to your application.
43
}
44
​
45
// Key stands for a AES key.
46
type Key []byte
47
​
48
func CBCDecrypt(key Key, cipherBytes []byte) ([]byte, error) {
49
block, err := aes.NewCipher(key)
50
if err != nil {
51
return nil, fmt.Errorf("failed to create new aes cipher with key [%s]. err(%s)",
52
key, err)
53
}
54
​
55
if len(cipherBytes) < aes.BlockSize {
56
return nil, errors.New("cipher bytes block size is too short")
57
}
58
​
59
// Use the beginning of the cipher as the initialization vector.
60
iv := cipherBytes[:aes.BlockSize]
61
cipherBytes = cipherBytes[aes.BlockSize:]
62
​
63
// Decrypt data in CBC mode.
64
mode := cipher.NewCBCDecrypter(block, iv)
65
decrypted := make([]byte, len(cipherBytes))
66
mode.CryptBlocks(decrypted, cipherBytes)
67
​
68
unpadded, err := unpad(decrypted)
69
if err != nil {
70
return nil, fmt.Errorf("failed to unpad data. err(%s)", err)
71
}
72
​
73
return unpadded, nil
74
}
75
​
76
// unpad removes the padding of a given byte array, according to the same rules
77
// as described in the pad function.
78
func unpad(padded []byte) ([]byte, error) {
79
paddedLen := len(padded)
80
if paddedLen == 0 {
81
return nil, errors.New("invalid padding size")
82
}
83
​
84
pad := padded[paddedLen-1]
85
padLen := int(pad)
86
if padLen > paddedLen || padLen > aes.BlockSize {
87
return nil, errors.New("invalid padding size")
88
}
89
​
90
for _, v := range padded[paddedLen-padLen : paddedLen-1] {
91
if v != pad {
92
return nil, errors.New("invalid padding")
93
}
94
}
95
​
96
return padded[:paddedLen-padLen], nil
97
}
Copied!
Last modified 1yr ago