BCSkill (Block chain skill )
区块链中文技术社区

只讨论区块链底层技术
遵守一切相关法律政策!

Cordova Android安全指南

内容安全政策

控制允许进行哪些网络请求(图像,XHR等)(直接通过webview)。

在Android和iOS上,网络请求白名单(见上文)无法过滤所有类型的请求(例如<video>,WebSockets未被阻止)。因此,除白名单外,您还应在所有网页上使用内容安全策略 <meta>标记。

在Android上,系统webview中对CSP的支持始于KitKat(但在使用Crosswalk WebView的所有版本上都可用)。

以下是您的.html网页的一些示例CSP声明:

<!-- Good default declaration:
    * gap: is required only on iOS (when using UIWebView) and is needed for JS->native communication
    * https://ssl.gstatic.com is required only on Android and is needed for TalkBack to function properly
    * Disables use of eval() and inline scripts in order to mitigate risk of XSS vulnerabilities. To change this:
        * Enable inline JS: add 'unsafe-inline' to default-src
        * Enable eval(): add 'unsafe-eval' to default-src
-->
<meta http-equiv="Content-Security-Policy" content="default-src 'self' data: gap: https://ssl.gstatic.com; style-src 'self' 'unsafe-inline'; media-src *">
<!-- Allow everything but only from the same origin and foo.com -->
<meta http-equiv="Content-Security-Policy" content="default-src 'self' foo.com">
<!-- This policy allows everything (eg CSS, AJAX, object, frame, media, etc) except that 
    * CSS only from the same origin and inline styles,
    * scripts only from the same origin and inline styles, and eval()
-->
<meta http-equiv="Content-Security-Policy" content="default-src *; style-src 'self' 'unsafe-inline'; script-src 'self' 'unsafe-inline' 'unsafe-eval'">
<!-- Allows XHRs only over HTTPS on the same domain. -->
<meta http-equiv="Content-Security-Policy" content="default-src 'self' https:">
<!-- Allow iframe to https://cordova.apache.org/ -->
<meta http-equiv="Content-Security-Policy" content="default-src 'self'; frame-src 'self' https://cordova.apache.org">

http://blog.inching.org/Cordova/2016-07-18-cordova-android-security-guide.html

李嘉图合同 - 关于区块链的具有法律约束力的协议

Live Contracts的想法一直挥之不去。以现存的李嘉图合同概念为例,它非常相似。李嘉图的合同源于20世纪90年代中期区块链技术和加密货币专家Ian Grigg所做的早期工作。

什么是李嘉图合同?

李嘉图的合同被认为是将合法有效和数字连接的文件注册到某个对象或价值的一种方式。Ricardian合同将法律文件中的所有信息以可由软件执行的格式放置。这样,它既可以是协议,也可以是在数字基础设施内安全地集成协议的协议,同时由于加密识别而提供高级别的安全性。

像普通的文本文档一样阅读

因此,李嘉图的合同对机器和人都是可读的。机器在数字基础设施中读取合同,人们将其作为纯文本文档阅读。这允许合同的所有各方正确处理其中所提供的信息。这种类型的合同将计算机语言与常规语言交织在一起,使交易成本更低:它可以有助于更快地解决争议,并且协议可以更容易地执行。

李嘉图合同的目的是什么?

李嘉图合同及其区块链技术的一个特点是其透明度。欺诈的风险可以保持在最低限度,因为使用加密哈希来完成特定数据的出版和参考。因此,代表金融交易(例如支付)的文件的数字化将在不久的将来变得越来越普遍。

李嘉图合同的定义

在20世纪90年代中期,Ian Grigg为数字资产运输的数字基础设施做出了重要贡献。这种模式被称为“里卡多”(以英国经济学家大卫里卡多的名字命名),由Systemics Inc.开发,这是一家专门从事金融交易,电子支付和密码学的美国公司。李嘉图的合同可以描述为:
“由发行人向财产所有人提交的单一文件形式的协议,其中所有者的所有权由文件的发行人管理。该文件必须清晰易读,就像传统的纸上合同一样。此外,协议必须通过程序和软件清晰可读,并使用数字密钥和服务器信息进行数字签名,并结合独特而安全的识别方法“。

英国经济学家大卫里卡多1772-1823

交易的发行和执行之间的严格分离

李嘉图的合同形成了立法与哈希函数创建的数字世界之间的联系。作为协议一部分的所有规则和条件都包含在合同中。在这样做时,交易问题及其执行是严格分开的,这反过来又有助于安全。李嘉图的合同规定了代理方之间达成的协议,因此这些方控制的程序可以执行本协议。

参考李嘉图合同的哈希值

该优惠以常规数字签名签署。通过同意涉及该合同散列的交易来接受合同。如果它涉及支付系统,则安全支付将参考该合同的散列,但也指付支付方和接收方。这种付款可以通过人工交易完成,但也可以通过智能合约进行。通过智能合约,交易的接受将基于智能合约代码进行。

隐藏的签名

有关各方签署的李嘉图合同是通过私钥完成的。合同提供者的签名被添加到文档中,该文档针对文档中描述的信息(例如属性)创建具有法律约束力且易读的提议。如果各方稍后参与李嘉图合同(例如,如果他们想要付款),则从签名的原始文档中覆盖加密“散列识别方法”。使用协议的哈希确保隐藏的签名附加到合同。

李嘉图合同和智能合约有什么区别?

智能合约是指已经达成一致且可以自动执行的一种数字协议。李嘉图合同是一种合同模型,用于记录合同的“意图”以及与合同相关的所有“行动”,甚至在合同执行之前。使用引用外部文档的哈希,Ricardian契约也可以轻松引用代码。毫无疑问,李嘉图的合同与未来的智能合约之间会有更多的交叉,交易可能会在不同的混合形式的基础上进行。

李嘉图的合同可以用于什么?

李嘉图合同可用于任何类型的协议。与智能合约不同,它不仅限于在诸如金融交易之类的简单情况下使用。李嘉道的合同用于确定代理方与另一方交易时的责任(责任)。合同代表某些商品或服务的单位。李嘉图的合同使用双方签署的协议,一旦签订合同,就不能伪造。

BowTie图

李嘉图的合同将各方之间的协议划分为时间和领域,并使用所谓的“BowTie图”。该图表以清晰的时间表显示某些风险。BowTie图表涉及谈判和起草具有法律约束力的合同,并明确了合同的所有目标。

立法

合同自动化的新解决方案可以成功,因为它们解决了法律实践中的实际问题。该技术仍处于全面发展阶段,其法律框架滞后。然而,在现有的立法框架内,李嘉图的合同已经可以接受。

LegalThings One是运行实时合同的平台。Token预售将于2017年12月6日开始。请访问livecontracts.io了解更多信息。

©与Ricardian合同相关的所有版权属于Systemics Inc.的I. Griggs先生。欲了解更多信息,请访问他的网站http://iang.org/并阅读他的白皮书http://iang.org/papers/ricardian_contract。 HTML

英文原文:https://medium.com/legalthingsone/ricardian-contracts-legally-binding-agreements-on-the-blockchain-4c103f120707

EOS delay transaction 延迟消息

交易可以设置delay_sec来指定延迟执行的时间,在合约中也提供了相应的API。

transaction out; //构造交易
out.actions.emplace_back(permission_level{_self, N(active)}, _self, N(test), std::make_tuple()); //将指定行为绑定到该交易上
out.delay_sec = 5; //设置延迟时间,单位为秒
out.send(_next_id(), _self, false); //发送交易,第一个参数为该次交易发送id,每次需不同。如果两个发送id相同,则视第三个参数replace_existing来定是覆盖还是直接失败。

另外需要注意的是可以在合约的某行为中发自身的延迟消息,于是可以达到定时任务的循环执行。
转载自(github

Scatter 身份获取部分代码

Dapp MonsterEOS 请求Scatter 获取身份信息

const network = {
  protocol: CHAIN_PROTOCOL,
  blockchain: 'eos',
  host: CHAIN_HOST,
  port: CHAIN_PORT,
  chainId: CHAIN_ID
}

app.ports.scatterRequestIdentity.subscribe(async () => {
    await scatter.suggestNetwork(network)
    let requiredFields = {
        accounts: [network]
    }
    scatter.getIdentity(requiredFields).then((identity) => {

      const user = {
          eosAccount: identity.accounts[0].name,
          publicKey: identity.publicKey
      }

      app.ports.setScatterIdentity.send(user)
    }).catch(error => {
      app.ports.scatterRejected.send("Identity or Network was rejected")
      console.error(error)
    })
})

开始进入Scatter 相关代码

Scatter\src\scatterdapp.js

suggestNetwork(network){
        if(!Network.fromJson(network).isValid()) throws('The provided network is invalid.');
        return _send(NetworkMessageTypes.REQUEST_ADD_NETWORK, {
            network:network
        });
    }

getIdentity(fields = {}){
        return _send(NetworkMessageTypes.GET_OR_REQUEST_IDENTITY, {
            network:network,
            fields
        }).then(async identity => {
            this.useIdentity(identity);
            return identity;
        });
    }

Scatter\src\content.js

 contentListener(msg){
        if(!isReady) return;
        if(!msg) return;
        if(!stream.synced && (!msg.hasOwnProperty('type') || msg.type !== 'sync')) {
            stream.send(nonSyncMessage.error(Error.maliciousEvent()), PairingTags.INJECTED);
            return;
        }

        // Always including the domain for every request.
        msg.domain = strippedHost();                           //此时domain被赋值
        if(msg.hasOwnProperty('payload'))
            msg.payload.domain = strippedHost();

        let nonSyncMessage = NetworkMessage.fromJson(msg);
        switch(msg.type){
            case 'sync': this.sync(msg); break;
            case NetworkMessageTypes.GET_OR_REQUEST_IDENTITY:           this.getOrRequestIdentity(nonSyncMessage); break;
getOrRequestIdentity(message){
        if(!isReady) return;
        InternalMessage.payload(InternalMessageTypes.GET_OR_REQUEST_IDENTITY, message.payload)
            .send().then(res => this.respond(message, res))
    }

Scatter\src\background.js

 dispenseMessage(sendResponse, message){
        Background.checkAutoLock();
        switch(message.type){
            case InternalMessageTypes.GET_OR_REQUEST_IDENTITY:          Background.getOrRequestIdentity(sendResponse, message.payload); break;

Scatter\src\background.js

static getOrRequestIdentity(sendResponse, payload){
        this.lockGuard(sendResponse, () => {
            Background.load(scatter => {
                const {domain, fields} = payload;

                IdentityService.getOrRequestIdentity(domain, fields, scatter, (identity, fromPermission) => {
                    if(!identity){
                        sendResponse(Error.signatureError("identity_rejected", "User rejected the provision of an Identity"));
                        return false;
                    }

                    if(!fromPermission) {
                        this.addHistory(HistoricEventTypes.PROVIDED_IDENTITY, {
                            domain,
                            provided:!!identity,
                            identityName:identity ? identity.name : false,
                            publicKey:(identity) ? identity.publicKey : false
                        });

                        this.addPermissions([Permission.fromJson({
                            domain,
                            identity:identity.publicKey,
                            timestamp:+ new Date(),
                            fields,
                            checksum:domain
                        })])
                    }

                    sendResponse(identity);
                });
            });
        })
    }

Scatter\src\services\IdentityService.js

 static identityFromPermissionsOrNull(domain, scatter){
        const identityFromPermission = IdentityService.identityPermission(domain, scatter);
        return identityFromPermission ? identityFromPermission.getIdentity(scatter.keychain) : null;
    }

    static getOrRequestIdentity(domain, fields, scatter, callback){

        // Possibly getting an Identity that has been synced with this application.
        const identityFromPermission = IdentityService.identityFromPermissionsOrNull(domain, scatter);
        let identity = identityFromPermission;

        const sendBackIdentity = id => {
            if(!id || id.hasOwnProperty('isError')){
                callback(null, null);
                return false;
            }

            callback(id.asOnlyRequiredFields(fields), !!identityFromPermission);
        };

        if(identity){
            // Even though there is a previous permission,
            // the identity might have changed and no longer
            // meets the requirements.
            if(identity.hasRequiredFields(fields)){
                sendBackIdentity(identity);
                return false;
            } else {
                // TODO: Remove permission
            }
        }
        else NotificationService.open(new Prompt(PromptTypes.REQUEST_IDENTITY, domain, null, fields, sendBackIdentity));  //进入此处开始下面逻辑
    }

Scatter\src\prompts\RequestIdentityPrompt.vue

methods: {
            bind(changed, original) { this[original] = changed },
            filteredIdentities(){
                return this.identities
                    .filter(id => id.hasRequiredFields(this.identityFields))
                    .filter(id => JSON.stringify(id).indexOf(this.searchText) !== -1)
            },
            formatProp(prop){
                if(prop instanceof Network) return `${prop.blockchain.toUpperCase()} Account`;
                return prop;
            },
            formatPropValue(identity, prop){
                const value = identity.getPropertyValueByName(prop);
                if(prop instanceof Network) return PluginRepository.plugin(prop.blockchain).accountFormatter(value);
                else if (prop === 'country') return value.name;
                return value;
            },
            selectIdentity(identity){
                this.selectedIdentity = identity;
            },
            accepted(){
                if(!this.selectedIdentity){
                    this[Actions.PUSH_ALERT](AlertMsg.YouMustSelectAnIdentity());
                    return false;
                }
                const identity = this.identities.find(id => id.publicKey === this.selectedIdentity.publicKey);
                this.prompt.responder(identity);
                NotificationService.close();
            },
            denied(){
                this.prompt.responder(null);
                NotificationService.close();
            },
            ...mapActions([
                Actions.UPDATE_STORED_SCATTER,
                Actions.PUSH_ALERT,
                Actions.PUSH_PROMPT
            ])
        }

Scatter\src\models\Identity.js

 /***
     * Checks if an Identity has specified fields.
     * This is used when an interacting application requires specific information.
     * @param fields - The fields to check for
     * @returns {boolean}
     */
    hasRequiredFields(fields){
        const requiredFields = IdentityRequiredFields.fromJson(fields);
        if(!requiredFields.isValid()) return false;

        if(requiredFields.personal.length)
            if(!requiredFields.personal.every(field => this.personal[field].length))
                return false;

        if(requiredFields.location.length)
            if(!this.locations.find(location => location.hasFields(requiredFields.location)))
                return false;

        if(requiredFields.accounts.length)
            if(!requiredFields.accounts.every(network => this.hasAccount(network)))
                return false;

        return true;
    }
 static placeholder(){ return new Identity(); }
    static fromJson(json){
        let p = Object.assign(this.placeholder(), json);
        if(json.hasOwnProperty('accounts')) p.accounts = Object.keys(json.accounts).reduce((acc, network) => {
            acc[network] = Account.fromJson(json.accounts[network]);
            return acc;
        }, {});
        p.personal = PersonalInformation.fromJson(json.personal);
        if(json.hasOwnProperty('locations')) p.locations = json.locations.map(location => LocationInformation.fromJson(location));
        else p.locations = [LocationInformation.placeholder()];
        return p;
    }

查找Scatter存储的身份中,选取网络匹配的账号,返回到界面,由用户选中

hasAccount(network){ return this.accounts.hasOwnProperty(network.unique()) }

Scatter\src\models\Network.js

unique(){ return (`${this.blockchain}:` + (this.chainId.length ? `chain:${this.chainId}` : `${this.host}:${this.port}`)).toLowerCase(); }

${this.blockchain} 为公链固定的类型,比如EOS为eos
如果Dapp配置了所需网络的chain Id,则计算返回为("${this.blockchain}:"+"chain:${this.chainId}").toLowerCase()
如果没有配置chain Id,则计算返回 ("${this.blockchain}:"+"${this.host}:${this.port}").toLowerCase()

总结

由于大多Dapp都配置了chain id,所以查找Scatter中相应的身份,及chain id相同网络设置的身份。


添加身份

Scatter\src\background.js

static addPermissions(permissions){
        this.load(scatter => {
            permissions.map(permission => {
                if(!scatter.keychain.hasPermission(permission.checksum, permission.fields))
                    scatter.keychain.permissions.unshift(permission);
            });
            this.update(() => {}, scatter);
        })
    }

附加background.js方法

在chrome打開地址 chrome://extensions/,點擊background page打開調試終端,開始調試。

EOS time_point_sec 时间计算

EOS专门对时间计算进行了封装,在eosiolib/time.hpp中提供了多种关于时间计算的封装,简单介绍一下time_point_sec的用法

auto time_now = time_point_sec(now()/*获取当前区块时间*/);
uint32_t five_minutes = 5 * 60;
five_minutes_later = time_now + five_minutes;
five_minutes_later > time_now;

得到的time_point_sec类型可以与uint32_t类型进行简单的加/减数值运算,同类型间也可以直接用大于/小于等比较符进行运算,满足大多数时间运算需求了已经。
转载自:github