예제 #1
0
def CreateWalletEndpoint(session, data):
    check_wallet_schema(data)
    pk = session.public_key
    invite_code = generate_random_string(48)

    if Wallet.select().where(Wallet.source == pk).exists():
        raise APIError("Shared wallet linked with your key is already exists", 409)

    level = data['participants'] - data['signers']

    device_uid = data.get('device_uid')
    wallet = Wallet.create(
        name=data['name'],
        signers=data['signers'],
        participants=data['participants'],
        invite_code=invite_code,
        level=level,
        source=pk)

    MultisigInfo.create(
        wallet=wallet.id,
        info=data['multisig_info'],
        level=0,
        device_uid=device_uid,
        source=pk)

    return jsonify({"invite_code": wallet.invite_code})
예제 #2
0
def ChangePublicKeyEndpoint(session, wallet, data):
    """Set multisig key instead of regular"""
    key = data['public_key']
    pk = session.public_key

    if wallet.status == "ready":
        changed_key = app.redis.hget("m_sessions", session.id)
        if changed_key is None:
            app.redis.hset("m_sessions", session.id, key)
        return ('', 200)

    # wallet = Wallet.get((Wallet.source == pk) | (Wallet.multisig_source == pk))
    if wallet.status not in ("changing_keys", "fulfilled"):
        raise APIError("Wallet is not ready for key change")

    # update wallet source if there is initiator key change request
    if wallet.source == pk:
        wallet.multisig_source = key
        wallet.save()

    # update multisig info source for this wallet and current session
    q = (MultisigInfo.update(
        multisig_source=key).where((MultisigInfo.source == pk)
                                   & (MultisigInfo.wallet == wallet)
                                   & (MultisigInfo.level == 0)))
    q.execute()

    changed_keys = MultisigInfo.select().where(
        (MultisigInfo.wallet == wallet) & (MultisigInfo.level == 0)
        & (MultisigInfo.multisig_source.is_null(False))).count()
    if changed_keys == wallet.participants:
        wallet.status = 'ready'
        wallet.save()

    app.redis.publish("stream:wallet_info:%s" % wallet.id, wallet.status)
    data = {
        'wallet_id': wallet.id,
        'public_key': pk,
        'status': wallet.status,
        'changed_keys': len(wallet.changed_keys),
        'joined': len(wallet.multisig_infos),
        'participants': wallet.participants,
        'signers': wallet.signers,
    }

    print(data)
    app.redis.publish("stream:wallet_info", json.dumps(data))

    # replace key in session
    app.redis.hset("m_sessions", session.id, key)

    return ('', 204)
예제 #3
0
def get_extra_multisig_info(wallet, level):
    multisigs = MultisigInfo.select().where((MultisigInfo.wallet == wallet)
                                            & (MultisigInfo.level == level))
    data = {
        "extra_multisig_infos": [{
            "extra_multisig_info": x.info
        } for x in multisigs]
    }

    return jsonify(data)
예제 #4
0
def setup_extra_multisig_info(wallet, fixed_level, extra_multisig_info, pk):
    level = wallet.participants - wallet.signers

    if not fixed_level:
        level_process = level + 1
        for i in range(1, level + 1):
            print(i)
            is_empty = LevelEmpty(wallet, i)
            if is_empty:
                level_process = i
                break
    else:
        level_process = fixed_level

    if level_process == level+1:
        if not wallet.is_changing_keys:
            wallet.status = "changing_keys"
            wallet.save()

            app.redis.publish("stream:extra_multisig_info:%s" % wallet.id, "complete")

            multisig_infos = MultisigInfo.select().where((MultisigInfo.wallet == wallet) & (MultisigInfo.level == level_process))
            data2 = {
                "wallet_id": wallet.id,
                "public_key": pk,
                "extra_multisig_infos": [{"extra_multisig_info": x.info} for x in multisig_infos]
            }
            app.redis.publish("stream:extra_multisig_info", json.dumps(data2))
    else:
        (info, created) = MultisigInfo.get_or_create(
            wallet=wallet.id,
            source=pk,
            level=level_process,
            defaults={"info": extra_multisig_info})

        if not created:
            info.info = extra_multisig_info
            info.save()
예제 #5
0
async def MultisigInfoStream(session, wallet, request):
    stream = await setup_stream(request)
    sub = None
    if wallet.is_new:
        sub = await wait_for_trigger('stream:multisig_info:%s' % wallet.id)

    multisig_infos = await objects.execute(
        MultisigInfo.select().where((MultisigInfo.wallet == wallet) & (MultisigInfo.level == 0))
    )
    data = {"multisig_infos": [{"multisig_info": x.info} for x in multisig_infos]}

    await write_and_close(stream, data, 'stream:multisig_info:%s' % wallet.id, sub)

    return stream
예제 #6
0
async def ExtraMultisigInfoStream(session, wallet, request):
    stream = setup_stream(request)

    if wallet.is_new or wallet.is_fulfilled:
        sub = await aioredis.create_redis('redis://localhost')
        subscriber = await sub.subscribe('stream:extra_multisig_info:%s' % wallet.id)
        subscriber = subscriber[0]

        while (await subscriber.wait_message()):
            msg = await subscriber.get()
            break

    multisig_infos = await objects.execute(
        MultisigInfo.select().where((MultisigInfo.wallet == wallet) & (MultisigInfo.level == 1))
    )
    data = {"extra_multisig_infos": [{"extra_multisig_info": x.info} for x in multisig_infos]}
    await write_and_close(stream, data, 'stream:multisig_info:%s' % wallet.id, sub)

    # using old state here
    if wallet.is_new or wallet.is_fulfilled:
        await sub.unsubscribe('stream:extra_multisig_info:%s' % wallet.id)

    return stream
예제 #7
0
def JoinWalletEndpoint(session, data):
    pk = session.public_key
    try:
        wallet = Wallet.get(invite_code=data['invite_code'])
    except Wallet.DoesNotExist:
        raise APIError("Wallet not found", status_code=404)

    device_uid = data.get('device_uid')
    if device_uid is not None:
        if MultisigInfo.select().where((MultisigInfo.device_uid == device_uid) &
                                   (MultisigInfo.wallet_id == wallet.id)).exists():
            raise APIError("Already joined", status_code=409)

    if not wallet.is_new:
        try:
            multisig = MultisigInfo.get(source=pk)
        except MultisigInfo.DoesNotExist:
            raise APIError("Wallet is already fulfilled", status_code=409)

        return ('', 200)

    (info, created) = MultisigInfo.get_or_create(
        wallet=wallet.id,
        source=pk,
        level=0,
        device_uid=device_uid,
        defaults={"info": data['multisig_info']})

    if not created:
        info.info = data['multisig_info']
        info.save()

    app.redis.publish("stream:wallet_info:%s" % wallet.id, wallet.status)
    data2 = {
        'wallet_id': wallet.id,
        'public_key': pk,
        'status': wallet.status,
        'changed_keys': len(wallet.changed_keys),
        'joined': len(wallet.multisig_infos),
        'participants': wallet.participants,
        'signers': wallet.signers,
        'event': 'joined'
    }
    app.redis.publish("stream:wallet_info", json.dumps(data2))

    if wallet.multisig_infos.count() >= wallet.participants:
        if wallet.level > 0:
            wallet.status = "fulfilled"
        else:
            wallet.status = "changing_keys"
        wallet.save()

        app.redis.publish("stream:multisig_info:%s" % wallet.id, "complete")
        data2 = {
            "wallet_id": wallet.id,
            "public_key": pk,
            "multisig_infos": [{"multisig_info": x.info} for x in wallet.multisig_infos],
            "event": "completed"
        }
        app.redis.publish("stream:multisig_info", json.dumps(data2))

    return ('', 204)
예제 #8
0
def LevelEmpty(wallet, level):
    infos_count = MultisigInfo.select().where((MultisigInfo.wallet == wallet) & (MultisigInfo.level == level)).count()
    if infos_count < wallet.participants:
        return True
    else:
        return False
예제 #9
0
def MultisigInfoEndpoint(session, wallet):
    multisigs = MultisigInfo.select().where((MultisigInfo.wallet == wallet)
                                            & (MultisigInfo.level == 0))
    data = {"multisig_infos": [{"multisig_info": x.info} for x in multisigs]}

    return jsonify(data)