summaryrefslogtreecommitdiff
path: root/src/attach.cpp
blob: 74bc875b3d6b68acc2abe83b3665da624d3f2dea (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
#include <erebos/attach.h>

#include "identity.h"
#include "pubkey.h"

#include <erebos/network.h>

#include <stdexcept>

using namespace erebos;
using std::lock_guard;
using std::nullopt;
using std::runtime_error;

static const UUID myUUID("4995a5f9-2d4d-48e9-ad3b-0bf1c2a1be7f");

AttachService::AttachService(Config && config, const Server &):
	PairingService(move(config))
{
}

AttachService::~AttachService() = default;

UUID AttachService::uuid() const
{
	return myUUID;
}

void AttachService::attachTo(const Peer & peer)
{
	requestPairing(myUUID, peer);
}

Stored<AttachIdentity> AttachService::handlePairingComplete(const Peer & peer)
{
	auto owner = peer.server().identity().finalOwner();
	auto id = peer.identity()->ref();
	auto prev = Stored<Signed<IdentityData>>::load(*peer.identity()->ref());

	auto idata = peer.tempStorage().store(IdentityData {
		.prev = { prev },
		.name = nullopt,
		.owner = Stored<Signed<IdentityData>>::load(*owner.ref()),
		.keyIdentity = prev->data->keyIdentity,
		.keyMessage = nullopt,
	});

	auto key = SecretKey::load(owner.keyIdentity());
	if (!key)
		throw runtime_error("failed to load secret key");

	auto mkey = SecretKey::load(owner.keyMessage());
	if (!mkey)
		throw runtime_error("failed to load secret key");

	auto sdata = key->sign(idata);

	return peer.tempStorage().store(AttachIdentity {
		.identity = sdata,
		.keys = { key->getData(), mkey->getData() },
	});
}

void AttachService::handlePairingResult(Context & ctx, Stored<AttachIdentity> att)
{
	if (att->identity->data->prev.size() != 1 ||
			att->identity->data->prev[0].ref().digest() !=
			ctx.local()->identity()->ref()->digest())
		return;

	if (att->identity->data->keyIdentity.ref().digest() !=
			ctx.local()->identity()->keyIdentity().ref().digest())
		return;

	auto key = SecretKey::load(ctx.peer().server().identity().keyIdentity());
	if (!key)
		throw runtime_error("failed to load secret key");

	auto id = Identity::load(key->signAdd(att->identity).ref());
	if (!id)
		printf("New identity validation failed\n");

	auto rid = ctx.local().ref().storage().copy(*id->ref());
	id = Identity::load(rid);

	auto owner = id->owner();
	if (!owner)
		printf("New identity without owner\n");

	// Store the keys
	for (const auto & k : att->keys) {
		SecretKey::fromData(owner->keyIdentity(), k);
		SecretKey::fromData(owner->keyMessage(), k);
	}

	ctx.local(ctx.local()->identity(*id));
}

AttachIdentity AttachIdentity::load(const Ref & ref)
{
	auto rec = ref->asRecord();
	if (!rec)
		return AttachIdentity {
			.identity = Stored<Signed<IdentityData>>::load(ref.storage().zref()),
			.keys = {},
		};

	return AttachIdentity {
		.identity = *rec->item("identity").as<Signed<IdentityData>>(),
		.keys = rec->items("skey").asBinary(),
	};
}

Ref AttachIdentity::store(const Storage & st) const
{
	vector<Record::Item> items;

	items.emplace_back("identity", identity.ref());
	for (const auto & key : keys)
		items.emplace_back("skey", key);

	return st.storeObject(Record(std::move(items)));
}