summaryrefslogtreecommitdiff
path: root/src/attach.cpp
blob: 887de38422656f34c1f2edeaa87ffe6a5fb5c839 (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
124
125
126
127
128
129
130
#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 pid = peer.identity();

	auto idata = peer.tempStorage().store(IdentityData {
		.prev = pid->data(),
		.name = nullopt,
		.owner = owner.data()[0],
		.keyIdentity = pid->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");

	vector<StoredIdentityPart> parts = ctx.local()->identity()->extData();
	parts.emplace_back(key->signAdd(att->identity));
	filterAncestors(parts);

	auto id = Identity::load(parts);
	if (!id)
		printf("New identity validation failed\n");

	optional<Ref> tmpref = id->extRef();
	if (not tmpref)
		tmpref = id->modify().commit().extRef();

	auto rid = ctx.local().ref().storage().copy(*tmpref);
	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)));
}