1 import { LocalStream } from 'extension-streams'
2 import InternalMessage from '@/messages/internal'
3 import * as MsgTypes from './messages/types'
4 import NotificationService from './services/NotificationService'
5 import StorageService from './services/StorageService'
6 import Prompt from './prompts/Prompt';
7 import * as PromptTypes from './prompts/PromptTypes'
8 import migrate from './migrations/migrator'
10 import _ from 'lodash'
11 import Error from './utils/errors/Error'
12 import { BTM, camelize } from './utils/constants'
14 import account from "@/models/account";
19 export default class Background {
21 this.setupInternalMessaging()
24 setupInternalMessaging() {
25 LocalStream.watch((request, sendResponse) => {
27 const message = InternalMessage.fromJson(request)
28 this.dispatchMessage(sendResponse, message)
32 dispatchMessage(sendResponse, message) {
33 switch (message.type) {
34 case MsgTypes.SETCHAIN:
35 Background.setChain(sendResponse, message.payload)
37 case MsgTypes.TRANSFER:
38 this.transfer(sendResponse, message.payload)
40 case MsgTypes.ADVTRANSFER:
41 this.advancedTransfer(sendResponse, message.payload)
44 this.send(sendResponse, message.payload)
46 case MsgTypes.SIGNTRANSACTION:
47 this.signTransaction(sendResponse, message.payload)
49 case MsgTypes.SIGNMESSAGE:
50 this.signMessage(sendResponse, message.payload)
52 case MsgTypes.REQUEST_CURRENT_ACCOUNT:
53 this.requestCurrentAccount(sendResponse, message.payload)
55 case MsgTypes.REQUEST_CURRENT_NETWORK:
56 this.requestCurrentNetwork(sendResponse)
58 case MsgTypes.REQUEST_CURRENT_CHAIN_TYPE:
59 this.requestCurrentChain(sendResponse)
62 Background.authenticate(sendResponse, message.payload)
64 case MsgTypes.DISABLE:
65 Background.disauthenticate(sendResponse, message.payload)
67 case MsgTypes.SET_PROMPT:
68 Background.setPrompt(sendResponse, message.payload);
70 case MsgTypes.GET_PROMPT:
71 Background.getPrompt(sendResponse);
74 Background.load(sendResponse);
77 Background.update(sendResponse, message.payload);
82 static setPrompt(sendResponse, notification){
83 prompt = notification;
87 static getPrompt(sendResponse){
91 signMessage(sendResponse, payload) {
92 var requestBody = payload.value
94 if(requestBody.address === undefined){
95 sendResponse(Error.typeMissed('address'));
98 if(requestBody.message === undefined){
99 sendResponse(Error.typeMissed('message'));
103 const {domain} = payload;
109 NotificationService.open(new Prompt(PromptTypes.REQUEST_PROMPT, domain, data ,approved => {
110 sendResponse(camelize(approved));
114 transfer(sendResponse, payload) {
115 var requestBody = payload.value
117 if(requestBody.from === undefined){
118 sendResponse(Error.typeMissed('from'));
121 if(requestBody.to === undefined){
122 sendResponse(Error.typeMissed('to'));
125 if(requestBody.asset === undefined){
126 sendResponse(Error.typeMissed('asset'));
130 const {domain} = payload;
136 NotificationService.open(new Prompt(PromptTypes.REQUEST_PROMPT, domain, data ,approved => {
137 sendResponse(camelize(approved));
141 advancedTransfer(sendResponse, payload) {
142 var requestBody = payload.value
144 if(requestBody.input === undefined){
145 sendResponse(Error.typeMissed('input'));
148 if(requestBody.output === undefined){
149 sendResponse(Error.typeMissed('output'));
152 if(requestBody.gas === undefined){
153 sendResponse(Error.typeMissed('gas'));
157 const {domain} = payload;
164 NotificationService.open(new Prompt(PromptTypes.REQUEST_PROMPT, domain, data ,approved => {
165 sendResponse(camelize(approved));
170 signTransaction(sendResponse, payload) {
171 const {domain, value} = payload;
175 type: 'signTransaction'
178 NotificationService.open(new Prompt(PromptTypes.REQUEST_PROMPT, domain, data ,approved => {
179 sendResponse(camelize(approved));
183 requestCurrentAccount(sendResponse, payload){
184 Background.load(bytom => {
185 const domain = payload.domain;
186 if(bytom.settings.domains.find(_domain => _domain === domain)) {
187 const currentAccount = bytom.currentAccount
188 const {vpAddress, address} = currentAccount
189 const classicAddress = currentAccount.bytom1.address
190 const isClassic = bytom.settings.netType === 'bytom1'
192 addresses: [vpAddress, isClassic?classicAddress:address],
193 rootXPub: currentAccount.xpub
195 if(bytom.settings.netType === 'vapor'){
196 account.address = vpAddress;
197 }else if(bytom.settings.netType === 'bytom1'){
198 account.address = classicAddress;
200 account.address = address;
203 sendResponse(account)
212 requestCurrentNetwork(sendResponse){
213 Background.load(bytom => {
214 sendResponse(bytom.settings.network);
218 requestCurrentChain(sendResponse){
219 Background.load(bytom => {
220 const chain = bytom.settings.netType ==='vapor'?'vapor':bytom.settings.netType==='bytom'?'bytom':bytom.settings.netType
225 send(sendResponse, payload) {
226 const action = payload.action
230 case 'listAllAccount':
231 promise = accountAction.list()
244 * Returns the saved instance of Bytom from the storage
245 * @param sendResponse - Delegating response handler
248 static load(sendResponse){
249 StorageService.get().then(async bytom => {
251 const migrated = await migrate(bytom);
252 if(migrated) this.update(() => {}, bytom);
258 * Updates the Scatter instance inside persistent storage
259 * @param sendResponse - Delegating response handler
260 * @param bytom - The updated cleartext Scatter instance
263 static update(sendResponse, bytom){
264 StorageService.save(bytom).then(saved => {
269 static setChain(sendResponse, newNetType) {
270 Background.load(bytom => {
271 const currentNet = bytom.settings.netType
273 if( newNetType !== currentNet){
274 bytom.settings.netType = newNetType;
275 this.update(() => sendResponse({status:'success'}), bytom);
277 sendResponse(Error.duplicate(newNetType));
282 static authenticate(sendResponse, payload){
283 Background.load(bytom => {
284 const {domain, ...domainAttrs} = payload;
286 const currentAccount = bytom.currentAccount
289 sendResponse(Error.signatureAccountMissing())
291 const {vpAddress, address} = currentAccount
292 const classicAddress = currentAccount.bytom1.address
293 const isClassic = bytom.settings.netType === 'bytom1'
297 addresses: [vpAddress, isClassic? classicAddress: address],
298 rootXPub: currentAccount.xpub,
300 xpub: currentAccount.xpub,
301 net: bytom.settings.network,
302 chain: bytom.settings.netType
304 if(bytom.settings.netType === 'vapor'){
305 account.address = vpAddress;
306 account.account = vpAddress
307 }else if(bytom.settings.netType === 'bytom1'){
308 account.address = classicAddress;
309 account.account = classicAddress
311 account.address = address;
312 account.account = address
316 if(bytom.settings.domains.find(_domain => _domain === domain)) {
317 sendResponse(account);
319 NotificationService.open(new Prompt(PromptTypes.REQUEST_AUTH, payload.domain, payload, approved => {
320 if (approved === false) sendResponse(Error.forbidden())
321 else if(approved.hasOwnProperty('isError')) sendResponse(approved);
323 bytom.settings.domains.unshift(domain);
324 bytom.settings.domainsMeta[domain] = domainAttrs;
326 if(approved === true){
327 this.update(() => sendResponse(account), bytom);
329 this.update(() => sendResponse(approved), bytom);
338 static disauthenticate(sendResponse, payload){
339 Background.load(bytom => {
340 const domain = payload.domain;
342 var index = bytom.settings.domains.indexOf(domain);
345 NotificationService.open(new Prompt(PromptTypes.REQUEST_AUTH, payload.domain, payload, approved => {
346 if (approved === false) sendResponse(Error.forbidden())
347 else if(approved.hasOwnProperty('isError')) sendResponse(approved);
349 bytom.settings.domains.splice(index, 1);
350 delete bytom.settings.domainsMeta[domain];
352 if(approved === true){
353 this.update(() => sendResponse({status:'success'}), bytom);
355 this.update(() => sendResponse(approved), bytom);
360 sendResponse(Error.disauth());
368 window.setLockTime = (time) => lockTime = time || Date.now();
369 window.getLockTime = () => lockTime;