Skip to content

Commit 2ad8fed

Browse files
committed
Add Third Party Caveat to macaroon demo
1 parent 7c1de4a commit 2ad8fed

File tree

6 files changed

+271
-30
lines changed

6 files changed

+271
-30
lines changed

libs/js/bitcoin.js

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -42374,16 +42374,22 @@ const ByteBuffer = class ByteBuffer {
4237442374
return this._buf.subarray(0, this._length);
4237542375
}
4237642376
/**
42377-
* Grow the internal buffer so that it's at least as but as minCap.
42377+
* Grow the internal buffer so that it's at least as big as minCap.
4237842378
* @param {int} minCap The minimum new capacity.
4237942379
*/
4238042380
_grow(minCap) {
42381-
if (minCap <= this._capacity) {
42381+
const capacity = this._buf.length;
42382+
if (minCap <= capacity) {
4238242383
return;
4238342384
}
42384-
// TODO could use more intelligent logic to grow more slowly on large buffers.
42385+
const fiftyPercent = Math.ceil(capacity * 1.5);
4238542386
const doubleCap = this._buf.length * 2;
42386-
const newCap = minCap > doubleCap ? minCap : doubleCap;
42387+
let newCap = minCap > doubleCap ? minCap : doubleCap;
42388+
// If the new capacity is only 1 to 9 bytes, try if increasing
42389+
// the buffer by 50% is enough.
42390+
if (minCap - capacity < 10 && minCap < fiftyPercent) {
42391+
newCap = fiftyPercent;
42392+
}
4238742393
const newContent = new Uint8Array(newCap);
4238842394
newContent.set(this._buf.subarray(0, this._length));
4238942395
this._buf = newContent;

libs/templates.js

Lines changed: 98 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -3229,7 +3229,25 @@ angular.module('app').run(['$templateCache', function($templateCache) {
32293229
" <div class=\"panel-collapse collapse\" ng-class=\"{in: vm.showExplanation}\">\n" +
32303230
" <div class=\"panel-body\">\n" +
32313231
" Macaroons are Cookies with Contextual Caveats for Decentralized Authorization in the Cloud.<br/><br/>\n" +
3232-
" They are used, for example, in the <em>lnd</em> implementation of the Lightning Network.\n" +
3232+
" They are used, for example, in the <em>lnd</em> implementation of the Lightning Network.<br/>\n" +
3233+
" A <strong>Caveat</strong> (or First Party Caveat) is a condition that is either added by the issuer of the\n" +
3234+
" macaroon or the user of the caveat. Because of the used cryptographic one-way function (HMAC), conditions can be added\n" +
3235+
" by anyone holding the macaroon, but nobody can remove any condition.<br/>\n" +
3236+
" That way, a user can further restrict the access rights of a macaroon that she obtained (for example, add a condition that\n" +
3237+
" the macaroon is only valid for the next 3 seconds while transmitting it over the internet and therefore restricting\n" +
3238+
" a potential eavesdropper's chance of using a stolen macaroon).<br/>\n" +
3239+
" The issuer of the macaroon (who is the holder of the private root key) can verify a signature even if further caveats have\n" +
3240+
" been added.<br/><br/>\n" +
3241+
" <strong>Third Party Caveats</strong> are conditions that have to be met by a third party. For example, a node operator wants\n" +
3242+
" to give all users of her website limited access to her LND node. She would then set up the LND node and the website with a\n" +
3243+
" <em>Shared Key</em>. The LND node would only issue macaroons that have a Third Party Caveat added for the website.<br/>\n" +
3244+
" This basically tells the macaroon validator that &quot;this macaroon is only valid if the user can also present a discharge macaroon\n" +
3245+
" from the service <code>website</code>&quot;.<br/>\n" +
3246+
" A user that is logged in to the website would then get a discharge macaroon that basically states &quot;I have been authorized by the\n" +
3247+
" service <code>website</code>&quot; and can prove that cryptographically.<br/>\n" +
3248+
" When the user wants to connect to the LND node and use its functionality, she would present both macaroons to the node that can\n" +
3249+
" then verify they both are valid, bound to each other and meet all conditions.\n" +
3250+
"\n" +
32333251
"\n" +
32343252
" <h3>Sources, tools and other useful information:</h3>\n" +
32353253
" <ul>\n" +
@@ -3252,12 +3270,12 @@ angular.module('app').run(['$templateCache', function($templateCache) {
32523270
" class=\"form-control\"\n" +
32533271
" ng-model=\"vm.rootKey\"\n" +
32543272
" ng-change=\"vm.newMacaroon()\"\n" +
3255-
" ng-class=\"{'well-error': vm.error}\">\n" +
3273+
" ng-class=\"{'well-error': vm.error2}\">\n" +
32563274
" <span class=\"input-group-addon\" ng-if=\"!vm.error2\">&lt;-- paste hex</span>\n" +
32573275
" <span class=\"input-group-addon well-error\" ng-if=\"vm.error2\"> {{vm.error2}}</span>\n" +
32583276
" <span class=\"input-group-btn\">\n" +
3259-
" <button class=\"btn btn-primary\" ng-click=\"vm.randomRootKey()\">Randomize</button>\n" +
3260-
" </span>\n" +
3277+
" <button class=\"btn btn-primary\" ng-click=\"vm.randomRootKey()\">Randomize</button>\n" +
3278+
" </span>\n" +
32613279
" </div>\n" +
32623280
" </div>\n" +
32633281
"\n" +
@@ -3289,17 +3307,60 @@ angular.module('app').run(['$templateCache', function($templateCache) {
32893307
" </div>\n" +
32903308
" <div class=\"form-group\">\n" +
32913309
" <div class=\"col-lg-offset-3 col-sm-9 input-group\">\n" +
3292-
" <div class=\"input-group-btn\">\n" +
3310+
" <div class=\"input-group\" style=\"width: 100%;\">\n" +
32933311
" <button class=\"btn btn-primary\" ng-click=\"vm.addCaveat()\">Add caveat</button>\n" +
3312+
" <button class=\"btn btn-secondary pull-right\" ng-if=\"!vm.thirdPartyMac\" ng-click=\"vm.addThirdPartyCaveat()\">\n" +
3313+
" Add third party caveat\n" +
3314+
" </button>\n" +
3315+
" <button class=\"btn btn-secondary pull-right\" ng-if=\"vm.thirdPartyMac\" ng-click=\"vm.removeThirdPartyCaveat()\">\n" +
3316+
" Remove third party caveat\n" +
3317+
" </button>\n" +
32943318
" </div>\n" +
32953319
" </div>\n" +
32963320
" </div>\n" +
32973321
"\n" +
3322+
" <!-- third party caveat -->\n" +
3323+
" <div class=\"form-group\" ng-if=\"vm.thirdPartyMac\">\n" +
3324+
" <label class=\"col-sm-3 control-label\">Third Party Caveat</label>\n" +
3325+
" <div class=\"col-sm-9 input-group\">\n" +
3326+
" <div class=\"input-group\">\n" +
3327+
" <div class=\"input-group-addon\">Shared Root key (hex):</div>\n" +
3328+
" <input class=\"form-control\"\n" +
3329+
" ng-model=\"vm.thirdPartyMac.rootKey\"\n" +
3330+
" ng-change=\"vm.newMacaroon()\"\n" +
3331+
" ng-class=\"{'well-error': vm.error4}\">\n" +
3332+
" <span class=\"input-group-addon\" ng-if=\"!vm.error4\">&lt;-- paste hex</span>\n" +
3333+
" <span class=\"input-group-addon well-error\" ng-if=\"vm.error4\"> {{vm.error4}}</span>\n" +
3334+
" <span class=\"input-group-btn\">\n" +
3335+
" <button class=\"btn btn-primary\" ng-click=\"vm.randomTpmRootKey()\">Randomize</button>\n" +
3336+
" </span>\n" +
3337+
" </div>\n" +
3338+
" <div class=\"input-group\">\n" +
3339+
" <div class=\"input-group-addon\">Identifier:</div>\n" +
3340+
" <input class=\"form-control\" ng-model=\"vm.thirdPartyMac.identifier\" ng-change=\"vm.newMacaroon()\">\n" +
3341+
" </div>\n" +
3342+
" <div class=\"input-group\">\n" +
3343+
" <div class=\"input-group-addon\">Location:</div>\n" +
3344+
" <input class=\"form-control\" ng-model=\"vm.thirdPartyMac.location\" ng-change=\"vm.newMacaroon()\">\n" +
3345+
" </div>\n" +
3346+
" </div>\n" +
3347+
" </div>\n" +
3348+
"\n" +
3349+
" <!-- discharge macaroon -->\n" +
3350+
" <div class=\"form-group\" ng-if=\"vm.thirdPartyMac\">\n" +
3351+
" <label class=\"col-sm-3 control-label\">Discharge macaroon from <br/>Third Party:</label>\n" +
3352+
" <div class=\"col-sm-9 input-group\">\n" +
3353+
" <input class=\"form-control\" value=\"{{ vm.serializeMacaroon(vm.thirdPartyMac.macaroon, false) }}\" ng-readonly=\"true\">\n" +
3354+
" </div>\n" +
3355+
" </div>\n" +
3356+
"\n" +
32983357
" <div class=\"form-group\">\n" +
32993358
" <label class=\"col-sm-3 control-label\" for=\"json\">JSON:</label>\n" +
33003359
" <div class=\"col-sm-9 input-group\">\n" +
3301-
" <textarea id=\"json2\" rows=\"10\" ng-readonly=\"true\"\n" +
3302-
" class=\"form-control\">{{ vm.serializeMacaroon(vm.macaroon2, vm.showJson) }}</textarea><br/>\n" +
3360+
" <textarea id=\"json2\" rows=\"10\" ng-readonly=\"true\" class=\"form-control\">{{\n" +
3361+
" vm.serializeMacaroon(vm.macaroon2, vm.showJson)\n" +
3362+
" }}</textarea>\n" +
3363+
" <br/>\n" +
33033364
" <input type=\"checkbox\" ng-model=\"vm.showJson\"> Show as JSON\n" +
33043365
" </div>\n" +
33053366
" </div>\n" +
@@ -3311,8 +3372,8 @@ angular.module('app').run(['$templateCache', function($templateCache) {
33113372
" <form class=\"form-horizontal\">\n" +
33123373
"\n" +
33133374
" <div class=\"form-group\">\n" +
3314-
" <label class=\"col-sm-3 control-label\" for=\"hash\">Hex serialized macaroon:</label>\n" +
3315-
" <div class=\"col-sm-9 input-group\">\n" +
3375+
" <label class=\"col-sm-4 control-label\" for=\"hash\">Hex serialized macaroon:</label>\n" +
3376+
" <div class=\"col-sm-8 input-group\">\n" +
33163377
" <input id=\"hash\"\n" +
33173378
" class=\"form-control\"\n" +
33183379
" ng-model=\"vm.encodedMacaroon\"\n" +
@@ -3324,12 +3385,38 @@ angular.module('app').run(['$templateCache', function($templateCache) {
33243385
" </div>\n" +
33253386
"\n" +
33263387
" <div class=\"form-group\">\n" +
3327-
" <label class=\"col-sm-3 control-label\" for=\"json\">Decoded as JSON:</label>\n" +
3328-
" <div class=\"col-sm-9 input-group\">\n" +
3388+
" <label class=\"col-sm-4 control-label\" for=\"json\">Decoded as JSON:</label>\n" +
3389+
" <div class=\"col-sm-8 input-group\">\n" +
33293390
" <textarea id=\"json\" rows=\"30\" ng-readonly=\"true\" class=\"form-control\">{{ vm.serializeMacaroon(vm.macaroon, true) }}</textarea>\n" +
33303391
" <input type=\"checkbox\" ng-model=\"vm.tryDecodingId\"> Try to decode identifier\n" +
33313392
" </div>\n" +
33323393
" </div>\n" +
3394+
"\n" +
3395+
" <!-- verify against root key -->\n" +
3396+
" <div class=\"form-group\">\n" +
3397+
" <label class=\"col-sm-4 control-label\" for=\"verificationRootKey\">Verify signature with root key:</label>\n" +
3398+
" <div class=\"col-sm-8 input-group\">\n" +
3399+
" <input id=\"verificationRootKey\"\n" +
3400+
" class=\"form-control\"\n" +
3401+
" ng-model=\"vm.verificationRootKey\"\n" +
3402+
" ng-change=\"vm.verifyMacaroon()\"\n" +
3403+
" ng-class=\"{'well-error': vm.error3, 'well-success': vm.valid}\">\n" +
3404+
" <span class=\"input-group-addon\" ng-if=\"!vm.error3\">&lt;-- paste hex</span>\n" +
3405+
" <span class=\"input-group-addon well-error\" ng-if=\"vm.error3\"> {{vm.error3}}</span>\n" +
3406+
" </div>\n" +
3407+
" </div>\n" +
3408+
"\n" +
3409+
" <!-- verify against root key -->\n" +
3410+
" <div class=\"form-group\">\n" +
3411+
" <label class=\"col-sm-4 control-label\" for=\"discharge\">Discharge macaroon<br/>(for Third Party Caveat verification):</label>\n" +
3412+
" <div class=\"col-sm-8 input-group\">\n" +
3413+
" <input id=\"discharge\"\n" +
3414+
" class=\"form-control\"\n" +
3415+
" ng-model=\"vm.verificationDischarge\"\n" +
3416+
" ng-change=\"vm.verifyMacaroon()\">\n" +
3417+
" <span class=\"input-group-addon\">&lt;-- paste hex</span>\n" +
3418+
" </div>\n" +
3419+
" </div>\n" +
33333420
" </form>\n" +
33343421
"</div>\n"
33353422
);

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@
3131
"grunt-angular-templates": "^1.1.0",
3232
"grunt-cli": "^1.3.2",
3333
"js-sha3": "^0.6.1",
34-
"macaroon": "^3.0.0",
34+
"macaroon": "guggero/js-macaroon",
3535
"merkle-lib": "^2.0.10",
3636
"pbkdf2": "^3.0.13",
3737
"pushdata-bitcoin": "^1.0.1",

pages/macaroon/macaroon.html

Lines changed: 98 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,25 @@ <h4 class="panel-title">
99
<div class="panel-collapse collapse" ng-class="{in: vm.showExplanation}">
1010
<div class="panel-body">
1111
Macaroons are Cookies with Contextual Caveats for Decentralized Authorization in the Cloud.<br/><br/>
12-
They are used, for example, in the <em>lnd</em> implementation of the Lightning Network.
12+
They are used, for example, in the <em>lnd</em> implementation of the Lightning Network.<br/>
13+
A <strong>Caveat</strong> (or First Party Caveat) is a condition that is either added by the issuer of the
14+
macaroon or the user of the caveat. Because of the used cryptographic one-way function (HMAC), conditions can be added
15+
by anyone holding the macaroon, but nobody can remove any condition.<br/>
16+
That way, a user can further restrict the access rights of a macaroon that she obtained (for example, add a condition that
17+
the macaroon is only valid for the next 3 seconds while transmitting it over the internet and therefore restricting
18+
a potential eavesdropper's chance of using a stolen macaroon).<br/>
19+
The issuer of the macaroon (who is the holder of the private root key) can verify a signature even if further caveats have
20+
been added.<br/><br/>
21+
<strong>Third Party Caveats</strong> are conditions that have to be met by a third party. For example, a node operator wants
22+
to give all users of her website limited access to her LND node. She would then set up the LND node and the website with a
23+
<em>Shared Key</em>. The LND node would only issue macaroons that have a Third Party Caveat added for the website.<br/>
24+
This basically tells the macaroon validator that &quot;this macaroon is only valid if the user can also present a discharge macaroon
25+
from the service <code>website</code>&quot;.<br/>
26+
A user that is logged in to the website would then get a discharge macaroon that basically states &quot;I have been authorized by the
27+
service <code>website</code>&quot; and can prove that cryptographically.<br/>
28+
When the user wants to connect to the LND node and use its functionality, she would present both macaroons to the node that can
29+
then verify they both are valid, bound to each other and meet all conditions.
30+
1331

1432
<h3>Sources, tools and other useful information:</h3>
1533
<ul>
@@ -32,12 +50,12 @@ <h4>Create macaroon</h4>
3250
class="form-control"
3351
ng-model="vm.rootKey"
3452
ng-change="vm.newMacaroon()"
35-
ng-class="{'well-error': vm.error}">
53+
ng-class="{'well-error': vm.error2}">
3654
<span class="input-group-addon" ng-if="!vm.error2">&lt;-- paste hex</span>
3755
<span class="input-group-addon well-error" ng-if="vm.error2"> {{vm.error2}}</span>
3856
<span class="input-group-btn">
39-
<button class="btn btn-primary" ng-click="vm.randomRootKey()">Randomize</button>
40-
</span>
57+
<button class="btn btn-primary" ng-click="vm.randomRootKey()">Randomize</button>
58+
</span>
4159
</div>
4260
</div>
4361

@@ -69,17 +87,60 @@ <h4>Create macaroon</h4>
6987
</div>
7088
<div class="form-group">
7189
<div class="col-lg-offset-3 col-sm-9 input-group">
72-
<div class="input-group-btn">
90+
<div class="input-group" style="width: 100%;">
7391
<button class="btn btn-primary" ng-click="vm.addCaveat()">Add caveat</button>
92+
<button class="btn btn-secondary pull-right" ng-if="!vm.thirdPartyMac" ng-click="vm.addThirdPartyCaveat()">
93+
Add third party caveat
94+
</button>
95+
<button class="btn btn-secondary pull-right" ng-if="vm.thirdPartyMac" ng-click="vm.removeThirdPartyCaveat()">
96+
Remove third party caveat
97+
</button>
98+
</div>
99+
</div>
100+
</div>
101+
102+
<!-- third party caveat -->
103+
<div class="form-group" ng-if="vm.thirdPartyMac">
104+
<label class="col-sm-3 control-label">Third Party Caveat</label>
105+
<div class="col-sm-9 input-group">
106+
<div class="input-group">
107+
<div class="input-group-addon">Shared Root key (hex):</div>
108+
<input class="form-control"
109+
ng-model="vm.thirdPartyMac.rootKey"
110+
ng-change="vm.newMacaroon()"
111+
ng-class="{'well-error': vm.error4}">
112+
<span class="input-group-addon" ng-if="!vm.error4">&lt;-- paste hex</span>
113+
<span class="input-group-addon well-error" ng-if="vm.error4"> {{vm.error4}}</span>
114+
<span class="input-group-btn">
115+
<button class="btn btn-primary" ng-click="vm.randomTpmRootKey()">Randomize</button>
116+
</span>
117+
</div>
118+
<div class="input-group">
119+
<div class="input-group-addon">Identifier:</div>
120+
<input class="form-control" ng-model="vm.thirdPartyMac.identifier" ng-change="vm.newMacaroon()">
74121
</div>
122+
<div class="input-group">
123+
<div class="input-group-addon">Location:</div>
124+
<input class="form-control" ng-model="vm.thirdPartyMac.location" ng-change="vm.newMacaroon()">
125+
</div>
126+
</div>
127+
</div>
128+
129+
<!-- discharge macaroon -->
130+
<div class="form-group" ng-if="vm.thirdPartyMac">
131+
<label class="col-sm-3 control-label">Discharge macaroon from <br/>Third Party:</label>
132+
<div class="col-sm-9 input-group">
133+
<input class="form-control" value="{{ vm.serializeMacaroon(vm.thirdPartyMac.macaroon, false) }}" ng-readonly="true">
75134
</div>
76135
</div>
77136

78137
<div class="form-group">
79138
<label class="col-sm-3 control-label" for="json">JSON:</label>
80139
<div class="col-sm-9 input-group">
81-
<textarea id="json2" rows="10" ng-readonly="true"
82-
class="form-control">{{ vm.serializeMacaroon(vm.macaroon2, vm.showJson) }}</textarea><br/>
140+
<textarea id="json2" rows="10" ng-readonly="true" class="form-control">{{
141+
vm.serializeMacaroon(vm.macaroon2, vm.showJson)
142+
}}</textarea>
143+
<br/>
83144
<input type="checkbox" ng-model="vm.showJson"> Show as JSON
84145
</div>
85146
</div>
@@ -91,8 +152,8 @@ <h4>Decode macaroon</h4>
91152
<form class="form-horizontal">
92153

93154
<div class="form-group">
94-
<label class="col-sm-3 control-label" for="hash">Hex serialized macaroon:</label>
95-
<div class="col-sm-9 input-group">
155+
<label class="col-sm-4 control-label" for="hash">Hex serialized macaroon:</label>
156+
<div class="col-sm-8 input-group">
96157
<input id="hash"
97158
class="form-control"
98159
ng-model="vm.encodedMacaroon"
@@ -104,11 +165,37 @@ <h4>Decode macaroon</h4>
104165
</div>
105166

106167
<div class="form-group">
107-
<label class="col-sm-3 control-label" for="json">Decoded as JSON:</label>
108-
<div class="col-sm-9 input-group">
168+
<label class="col-sm-4 control-label" for="json">Decoded as JSON:</label>
169+
<div class="col-sm-8 input-group">
109170
<textarea id="json" rows="30" ng-readonly="true" class="form-control">{{ vm.serializeMacaroon(vm.macaroon, true) }}</textarea>
110171
<input type="checkbox" ng-model="vm.tryDecodingId"> Try to decode identifier
111172
</div>
112173
</div>
174+
175+
<!-- verify against root key -->
176+
<div class="form-group">
177+
<label class="col-sm-4 control-label" for="verificationRootKey">Verify signature with root key:</label>
178+
<div class="col-sm-8 input-group">
179+
<input id="verificationRootKey"
180+
class="form-control"
181+
ng-model="vm.verificationRootKey"
182+
ng-change="vm.verifyMacaroon()"
183+
ng-class="{'well-error': vm.error3, 'well-success': vm.valid}">
184+
<span class="input-group-addon" ng-if="!vm.error3">&lt;-- paste hex</span>
185+
<span class="input-group-addon well-error" ng-if="vm.error3"> {{vm.error3}}</span>
186+
</div>
187+
</div>
188+
189+
<!-- verify against root key -->
190+
<div class="form-group">
191+
<label class="col-sm-4 control-label" for="discharge">Discharge macaroon<br/>(for Third Party Caveat verification):</label>
192+
<div class="col-sm-8 input-group">
193+
<input id="discharge"
194+
class="form-control"
195+
ng-model="vm.verificationDischarge"
196+
ng-change="vm.verifyMacaroon()">
197+
<span class="input-group-addon">&lt;-- paste hex</span>
198+
</div>
199+
</div>
113200
</form>
114201
</div>

0 commit comments

Comments
 (0)