Merge branch 'decode2' into decode3
Change-Id: I1551d440da0f2c9198d8aec72c089f8c05188a67
diff --git a/.gitignore b/.gitignore
index cd0b069..5854afc 100644
--- a/.gitignore
+++ b/.gitignore
@@ -14,6 +14,7 @@
go/bin
xunit.xml
tmp
+.idea
# Vanadium
/.v23
diff --git a/extension/manifest.json b/extension/manifest.json
index ab38291..f2e9a2e 100644
--- a/extension/manifest.json
+++ b/extension/manifest.json
@@ -1,6 +1,6 @@
{
"name": "Vanadium Extension",
- "version": "0.1.8",
+ "version": "0.1.9",
"description": "Access and create Vanadium services from JavaScript.",
"manifest_version": 2,
"icons": {
diff --git a/src/gen-vdl/v.io/v23/vom/testdata/index.js b/src/gen-vdl/v.io/v23/vom/testdata/index.js
index 6757508..c1e5296 100644
--- a/src/gen-vdl/v.io/v23/vom/testdata/index.js
+++ b/src/gen-vdl/v.io/v23/vom/testdata/index.js
@@ -22,6 +22,8 @@
var _type12 = new vdl.Type();
var _type13 = new vdl.Type();
var _type14 = new vdl.Type();
+var _type15 = new vdl.Type();
+var _type16 = new vdl.Type();
var _type2 = new vdl.Type();
var _type3 = new vdl.Type();
var _type4 = new vdl.Type();
@@ -85,6 +87,8 @@
var _typeSetOnlyMap = new vdl.Type();
var _typeSetStructMap = new vdl.Type();
var _typeSometimesSetMap = new vdl.Type();
+var _typeStructAny = new vdl.Type();
+var _typeStructMap = new vdl.Type();
var _typeStructOnlyMap = new vdl.Type();
var _typeTestCase = new vdl.Type();
var _typeVomdataStruct = new vdl.Type();
@@ -94,22 +98,29 @@
_type1.kind = vdl.kind.LIST;
_type1.name = "";
_type1.elem = _typeTestCase;
-_type10.kind = vdl.kind.LIST;
+_type10.kind = vdl.kind.MAP;
_type10.name = "";
-_type10.elem = vdl.types.INT32;
+_type10.elem = _type11;
+_type10.key = vdl.types.STRING;
_type11.kind = vdl.kind.LIST;
_type11.name = "";
-_type11.elem = vdl.types.STRING;
-_type12.kind = vdl.kind.MAP;
+_type11.elem = vdl.types.TYPEOBJECT;
+_type12.kind = vdl.kind.LIST;
_type12.name = "";
-_type12.elem = _type13;
-_type12.key = vdl.types.STRING;
+_type12.elem = vdl.types.INT32;
_type13.kind = vdl.kind.LIST;
_type13.name = "";
-_type13.elem = _typeConvertGroup;
-_type14.kind = vdl.kind.LIST;
+_type13.elem = vdl.types.STRING;
+_type14.kind = vdl.kind.MAP;
_type14.name = "";
-_type14.elem = vdl.types.ANY;
+_type14.elem = _type15;
+_type14.key = vdl.types.STRING;
+_type15.kind = vdl.kind.LIST;
+_type15.name = "";
+_type15.elem = _typeConvertGroup;
+_type16.kind = vdl.kind.LIST;
+_type16.name = "";
+_type16.elem = vdl.types.ANY;
_type2.kind = vdl.kind.LIST;
_type2.name = "";
_type2.elem = vdl.types.BYTE;
@@ -131,11 +142,11 @@
_type7.elem = _typeRecStruct;
_type8.kind = vdl.kind.MAP;
_type8.name = "";
-_type8.elem = _type9;
-_type8.key = vdl.types.STRING;
-_type9.kind = vdl.kind.LIST;
+_type8.elem = vdl.types.INT64;
+_type8.key = vdl.types.INT64;
+_type9.kind = vdl.kind.OPTIONAL;
_type9.name = "";
-_type9.elem = vdl.types.TYPEOBJECT;
+_type9.elem = _typeStructAny;
_typeAbcStruct.kind = vdl.kind.STRUCT;
_typeAbcStruct.name = "v.io/v23/vom/testdata.AbcStruct";
_typeAbcStruct.fields = [{name: "A", type: vdl.types.BOOL}, {name: "B", type: vdl.types.STRING}, {name: "C", type: vdl.types.INT64}];
@@ -161,7 +172,7 @@
_typeBrieEnum.labels = ["Glee", "Brie", "Three"];
_typeConvertGroup.kind = vdl.kind.STRUCT;
_typeConvertGroup.name = "v.io/v23/vom/testdata.ConvertGroup";
-_typeConvertGroup.fields = [{name: "Name", type: vdl.types.STRING}, {name: "PrimaryType", type: vdl.types.TYPEOBJECT}, {name: "Values", type: _type14}];
+_typeConvertGroup.fields = [{name: "Name", type: vdl.types.STRING}, {name: "PrimaryType", type: vdl.types.TYPEOBJECT}, {name: "Values", type: _type16}];
_typeFoodEnum.kind = vdl.kind.ENUM;
_typeFoodEnum.name = "v.io/v23/vom/testdata.FoodEnum";
_typeFoodEnum.labels = ["Bean", "Brie", "Cherry"];
@@ -300,6 +311,12 @@
_typeSometimesSetMap.name = "v.io/v23/vom/testdata.SometimesSetMap";
_typeSometimesSetMap.elem = vdl.types.ANY;
_typeSometimesSetMap.key = vdl.types.FLOAT64;
+_typeStructAny.kind = vdl.kind.STRUCT;
+_typeStructAny.name = "v.io/v23/vom/testdata.StructAny";
+_typeStructAny.fields = [{name: "Any", type: vdl.types.ANY}];
+_typeStructMap.kind = vdl.kind.STRUCT;
+_typeStructMap.name = "v.io/v23/vom/testdata.StructMap";
+_typeStructMap.fields = [{name: "Map", type: _type8}];
_typeStructOnlyMap.kind = vdl.kind.MAP;
_typeStructOnlyMap.name = "v.io/v23/vom/testdata.StructOnlyMap";
_typeStructOnlyMap.elem = vdl.types.UINT64;
@@ -309,7 +326,7 @@
_typeTestCase.fields = [{name: "Name", type: vdl.types.STRING}, {name: "Value", type: vdl.types.ANY}, {name: "TypeString", type: vdl.types.STRING}, {name: "Hex", type: vdl.types.STRING}, {name: "HexVersion", type: vdl.types.STRING}, {name: "HexType", type: vdl.types.STRING}, {name: "HexValue", type: vdl.types.STRING}];
_typeVomdataStruct.kind = vdl.kind.STRUCT;
_typeVomdataStruct.name = "v.io/v23/vom/testdata.VomdataStruct";
-_typeVomdataStruct.fields = [{name: "EncodeDecodeData", type: _type14}, {name: "CompatData", type: _type8}, {name: "ConvertData", type: _type12}];
+_typeVomdataStruct.fields = [{name: "EncodeDecodeData", type: _type16}, {name: "CompatData", type: _type10}, {name: "ConvertData", type: _type14}];
_typeXyzStruct.kind = vdl.kind.STRUCT;
_typeXyzStruct.name = "v.io/v23/vom/testdata.XyzStruct";
_typeXyzStruct.fields = [{name: "X", type: vdl.types.BOOL}, {name: "Y", type: _typeMBool}, {name: "Z", type: vdl.types.STRING}];
@@ -325,6 +342,8 @@
_type12.freeze();
_type13.freeze();
_type14.freeze();
+_type15.freeze();
+_type16.freeze();
_type2.freeze();
_type3.freeze();
_type4.freeze();
@@ -388,6 +407,8 @@
_typeSetOnlyMap.freeze();
_typeSetStructMap.freeze();
_typeSometimesSetMap.freeze();
+_typeStructAny.freeze();
+_typeStructMap.freeze();
_typeStructOnlyMap.freeze();
_typeTestCase.freeze();
_typeVomdataStruct.freeze();
@@ -463,6 +484,8 @@
module.exports.SetOnlyMap = (vdl.registry.lookupOrCreateConstructor(_typeSetOnlyMap));
module.exports.SetStructMap = (vdl.registry.lookupOrCreateConstructor(_typeSetStructMap));
module.exports.SometimesSetMap = (vdl.registry.lookupOrCreateConstructor(_typeSometimesSetMap));
+module.exports.StructAny = (vdl.registry.lookupOrCreateConstructor(_typeStructAny));
+module.exports.StructMap = (vdl.registry.lookupOrCreateConstructor(_typeStructMap));
module.exports.StructOnlyMap = (vdl.registry.lookupOrCreateConstructor(_typeStructOnlyMap));
module.exports.TestCase = (vdl.registry.lookupOrCreateConstructor(_typeTestCase));
module.exports.VomdataStruct = (vdl.registry.lookupOrCreateConstructor(_typeVomdataStruct));
@@ -2796,9 +2819,116 @@
'hexType': "513407001c762e696f2f7632332f766f6d2f74657374646174612e4e556e696f6e01030001410101e10001420103e10001430109e1e1",
'hexValue': "1c29",
},
+{
+ 'name': "StructAny{}",
+ 'value': canonicalize.reduce(new (vdl.registry.lookupOrCreateConstructor(_typeStructAny))({
+ 'any': null,
+}, true), _typeStructAny),
+ 'typeString': "v.io/v23/vom/testdata.StructAny struct{Any any}",
+ 'hex': "80512d06001f762e696f2f7632332f766f6d2f74657374646174612e537472756374416e7901010003416e79010fe1e15201e1",
+ 'hexVersion': "80",
+ 'hexType': "512d06001f762e696f2f7632332f766f6d2f74657374646174612e537472756374416e7901010003416e79010fe1e1",
+ 'hexValue': "5201e1",
+},
+{
+ 'name': "StructAny{Any: false}",
+ 'value': canonicalize.reduce(new (vdl.registry.lookupOrCreateConstructor(_typeStructAny))({
+ 'any': canonicalize.reduce(new (vdl.registry.lookupOrCreateConstructor(vdl.types.BOOL))(false, true), vdl.types.BOOL),
+}, true), _typeStructAny),
+ 'typeString': "v.io/v23/vom/testdata.StructAny struct{Any any}",
+ 'hex': "80512d06001f762e696f2f7632332f766f6d2f74657374646174612e537472756374416e7901010003416e79010fe1e15204000100e1",
+ 'hexVersion': "80",
+ 'hexType': "512d06001f762e696f2f7632332f766f6d2f74657374646174612e537472756374416e7901010003416e79010fe1e1",
+ 'hexValue': "5204000100e1",
+},
+{
+ 'name': "StructAny{Any: StructMap{}}",
+ 'value': canonicalize.reduce(new (vdl.registry.lookupOrCreateConstructor(_typeStructAny))({
+ 'any': canonicalize.reduce(new (vdl.registry.lookupOrCreateConstructor(_typeStructMap))({
+ 'map': new Map([]),
+}, true), _typeStructMap),
+}, true), _typeStructAny),
+ 'typeString': "v.io/v23/vom/testdata.StructAny struct{Any any}",
+ 'hex': "80512d06001f762e696f2f7632332f766f6d2f74657374646174612e537472756374416e7901010003416e79010fe1e155060501090209e1532d06001f762e696f2f7632332f766f6d2f74657374646174612e5374727563744d6170010100034d6170012be1e15204002ae1e1",
+ 'hexVersion': "80",
+ 'hexType': "512d06001f762e696f2f7632332f766f6d2f74657374646174612e537472756374416e7901010003416e79010fe1e155060501090209e1532d06001f762e696f2f7632332f766f6d2f74657374646174612e5374727563744d6170010100034d6170012be1e1",
+ 'hexValue': "5204002ae1e1",
+},
+{
+ 'name': "StructAny{Any: StructMap{Map: {0: 0}}}",
+ 'value': canonicalize.reduce(new (vdl.registry.lookupOrCreateConstructor(_typeStructAny))({
+ 'any': canonicalize.reduce(new (vdl.registry.lookupOrCreateConstructor(_typeStructMap))({
+ 'map': new Map([
+ [new vdl.BigInt(0, new Uint8Array([])), new vdl.BigInt(0, new Uint8Array([]))]]),
+}, true), _typeStructMap),
+}, true), _typeStructAny),
+ 'typeString': "v.io/v23/vom/testdata.StructAny struct{Any any}",
+ 'hex': "80512d06001f762e696f2f7632332f766f6d2f74657374646174612e537472756374416e7901010003416e79010fe1e155060501090209e1532d06001f762e696f2f7632332f766f6d2f74657374646174612e5374727563744d6170010100034d6170012be1e15208002a00010000e1e1",
+ 'hexVersion': "80",
+ 'hexType': "512d06001f762e696f2f7632332f766f6d2f74657374646174612e537472756374416e7901010003416e79010fe1e155060501090209e1532d06001f762e696f2f7632332f766f6d2f74657374646174612e5374727563744d6170010100034d6170012be1e1",
+ 'hexValue': "5208002a00010000e1e1",
+},
+{
+ 'name': "?StructAny(nil)",
+ 'value': canonicalize.reduce(new (vdl.registry.lookupOrCreateConstructor(_type9))(null, true), _type9),
+ 'typeString': "?v.io/v23/vom/testdata.StructAny struct{Any any}",
+ 'hex': "80532d06001f762e696f2f7632332f766f6d2f74657374646174612e537472756374416e7901010003416e79010fe1e1510408012ae15201e0",
+ 'hexVersion': "80",
+ 'hexType': "532d06001f762e696f2f7632332f766f6d2f74657374646174612e537472756374416e7901010003416e79010fe1e1510408012ae1",
+ 'hexValue': "5201e0",
+},
+{
+ 'name': "?StructAny{}",
+ 'value': canonicalize.reduce(new (vdl.registry.lookupOrCreateConstructor(_type9))({
+ 'any': null,
+}, true), _type9),
+ 'typeString': "?v.io/v23/vom/testdata.StructAny struct{Any any}",
+ 'hex': "80532d06001f762e696f2f7632332f766f6d2f74657374646174612e537472756374416e7901010003416e79010fe1e1510408012ae15201e1",
+ 'hexVersion': "80",
+ 'hexType': "532d06001f762e696f2f7632332f766f6d2f74657374646174612e537472756374416e7901010003416e79010fe1e1510408012ae1",
+ 'hexValue': "5201e1",
+},
+{
+ 'name': "?StructAny{Any: false}",
+ 'value': canonicalize.reduce(new (vdl.registry.lookupOrCreateConstructor(_type9))({
+ 'any': canonicalize.reduce(new (vdl.registry.lookupOrCreateConstructor(vdl.types.BOOL))(false, true), vdl.types.BOOL),
+}, true), _type9),
+ 'typeString': "?v.io/v23/vom/testdata.StructAny struct{Any any}",
+ 'hex': "80532d06001f762e696f2f7632332f766f6d2f74657374646174612e537472756374416e7901010003416e79010fe1e1510408012ae15204000100e1",
+ 'hexVersion': "80",
+ 'hexType': "532d06001f762e696f2f7632332f766f6d2f74657374646174612e537472756374416e7901010003416e79010fe1e1510408012ae1",
+ 'hexValue': "5204000100e1",
+},
+{
+ 'name': "?StructAny{Any: StructMap{}}",
+ 'value': canonicalize.reduce(new (vdl.registry.lookupOrCreateConstructor(_type9))({
+ 'any': canonicalize.reduce(new (vdl.registry.lookupOrCreateConstructor(_typeStructMap))({
+ 'map': new Map([]),
+}, true), _typeStructMap),
+}, true), _type9),
+ 'typeString': "?v.io/v23/vom/testdata.StructAny struct{Any any}",
+ 'hex': "80532d06001f762e696f2f7632332f766f6d2f74657374646174612e537472756374416e7901010003416e79010fe1e1510408012ae157060501090209e1552d06001f762e696f2f7632332f766f6d2f74657374646174612e5374727563744d6170010100034d6170012ce1e15204002be1e1",
+ 'hexVersion': "80",
+ 'hexType': "532d06001f762e696f2f7632332f766f6d2f74657374646174612e537472756374416e7901010003416e79010fe1e1510408012ae157060501090209e1552d06001f762e696f2f7632332f766f6d2f74657374646174612e5374727563744d6170010100034d6170012ce1e1",
+ 'hexValue': "5204002be1e1",
+},
+{
+ 'name': "?StructAny{Any: StructMap{Map: {0: 0}}}",
+ 'value': canonicalize.reduce(new (vdl.registry.lookupOrCreateConstructor(_type9))({
+ 'any': canonicalize.reduce(new (vdl.registry.lookupOrCreateConstructor(_typeStructMap))({
+ 'map': new Map([
+ [new vdl.BigInt(0, new Uint8Array([])), new vdl.BigInt(0, new Uint8Array([]))]]),
+}, true), _typeStructMap),
+}, true), _type9),
+ 'typeString': "?v.io/v23/vom/testdata.StructAny struct{Any any}",
+ 'hex': "80532d06001f762e696f2f7632332f766f6d2f74657374646174612e537472756374416e7901010003416e79010fe1e1510408012ae157060501090209e1552d06001f762e696f2f7632332f766f6d2f74657374646174612e5374727563744d6170010100034d6170012ce1e15208002b00010000e1e1",
+ 'hexVersion': "80",
+ 'hexType': "532d06001f762e696f2f7632332f766f6d2f74657374646174612e537472756374416e7901010003416e79010fe1e1510408012ae157060501090209e1552d06001f762e696f2f7632332f766f6d2f74657374646174612e5374727563744d6170010100034d6170012ce1e1",
+ 'hexValue': "5208002b00010000e1e1",
+},
], true), _type1);
- module.exports.CompatTests = canonicalize.reduce(new (vdl.registry.lookupOrCreateConstructor(_type8))(new Map([
+ module.exports.CompatTests = canonicalize.reduce(new (vdl.registry.lookupOrCreateConstructor(_type10))(new Map([
["bool", [
vdl.types.BOOL,
_typeNBool,
@@ -2819,7 +2949,7 @@
_typeMapStructSet,
]],
["number list/array", [
-_type10,
+_type12,
_typeNArray2Uint64,
_typeNListUint64,
]],
@@ -2846,7 +2976,7 @@
_typeNComplex128,
]],
["string list/array", [
-_type11,
+_type13,
_typeListString,
_typeArray3String,
_typeArray4String,
@@ -2875,9 +3005,9 @@
["union B", [
_typeNUnion,
_typeBdeUnion,
-]]]), true), _type8);
+]]]), true), _type10);
- module.exports.ConvertTests = canonicalize.reduce(new (vdl.registry.lookupOrCreateConstructor(_type12))(new Map([
+ module.exports.ConvertTests = canonicalize.reduce(new (vdl.registry.lookupOrCreateConstructor(_type14))(new Map([
["array/list", [
{
'name': "[3]string",
@@ -2888,11 +3018,11 @@
"B",
"C",
], true), _typeArray3String),
-canonicalize.reduce(new (vdl.registry.lookupOrCreateConstructor(_type11))([
+canonicalize.reduce(new (vdl.registry.lookupOrCreateConstructor(_type13))([
"A",
"B",
"C",
-], true), _type11),
+], true), _type13),
],
},
{
@@ -3247,7 +3377,7 @@
canonicalize.reduce(new (vdl.registry.lookupOrCreateConstructor(_typeNUnion))({ "a": true }, true), _typeNUnion),
],
},
-]]]), true), _type12);
+]]]), true), _type14);
diff --git a/src/gen-vdl/v.io/x/ref/services/wspr/internal/app/index.js b/src/gen-vdl/v.io/x/ref/services/wspr/internal/app/index.js
index 5850954..8ff3aad 100644
--- a/src/gen-vdl/v.io/x/ref/services/wspr/internal/app/index.js
+++ b/src/gen-vdl/v.io/x/ref/services/wspr/internal/app/index.js
@@ -22,7 +22,6 @@
// Types:
var _type1 = new vdl.Type();
-var _type10 = new vdl.Type();
var _type2 = new vdl.Type();
var _type3 = new vdl.Type();
var _type4 = new vdl.Type();
@@ -41,9 +40,6 @@
_type1.kind = vdl.kind.LIST;
_type1.name = "";
_type1.elem = _typeRpcCallOption;
-_type10.kind = vdl.kind.LIST;
-_type10.name = "";
-_type10.elem = new principal.BlessingsHandle()._type;
_type2.kind = vdl.kind.LIST;
_type2.name = "";
_type2.elem = new security.BlessingPattern()._type;
@@ -56,19 +52,19 @@
_type5.kind = vdl.kind.LIST;
_type5.name = "";
_type5.elem = new security.Caveat()._type;
-_type6.kind = vdl.kind.OPTIONAL;
+_type6.kind = vdl.kind.LIST;
_type6.name = "";
-_type6.elem = new principal.JsBlessings()._type;
-_type7.kind = vdl.kind.LIST;
+_type6.elem = vdl.types.STRING;
+_type7.kind = vdl.kind.MAP;
_type7.name = "";
-_type7.elem = vdl.types.STRING;
-_type8.kind = vdl.kind.MAP;
+_type7.elem = new principal.BlessingsId()._type;
+_type7.key = new security.BlessingPattern()._type;
+_type8.kind = vdl.kind.LIST;
_type8.name = "";
-_type8.elem = _type6;
-_type8.key = new security.BlessingPattern()._type;
+_type8.elem = new signature.Interface()._type;
_type9.kind = vdl.kind.LIST;
_type9.name = "";
-_type9.elem = new signature.Interface()._type;
+_type9.elem = new principal.BlessingsHandle()._type;
_typeGranterHandle.kind = vdl.kind.INT32;
_typeGranterHandle.name = "v.io/x/ref/services/wspr/internal/app.GranterHandle";
_typeGranterRequest.kind = vdl.kind.STRUCT;
@@ -90,7 +86,6 @@
_typeRpcServerOption.name = "v.io/x/ref/services/wspr/internal/app.RpcServerOption";
_typeRpcServerOption.fields = [{name: "IsLeaf", type: vdl.types.BOOL}, {name: "ServesMountTable", type: vdl.types.BOOL}];
_type1.freeze();
-_type10.freeze();
_type2.freeze();
_type3.freeze();
_type4.freeze();
@@ -386,14 +381,9 @@
},
],
outArgs: [{
- name: 'publicKeyOut',
+ name: '',
doc: "",
- type: vdl.types.STRING
- },
- {
- name: 'handleOut',
- doc: "",
- type: new principal.BlessingsHandle()._type
+ type: new principal.BlessingsId()._type
},
],
inStream: null,
@@ -417,14 +407,9 @@
},
],
outArgs: [{
- name: 'publicKeyOut',
+ name: '',
doc: "",
- type: vdl.types.STRING
- },
- {
- name: 'handleOut',
- doc: "",
- type: new principal.BlessingsHandle()._type
+ type: new principal.BlessingsId()._type
},
],
inStream: null,
@@ -466,7 +451,7 @@
outArgs: [{
name: '',
doc: "",
- type: _type6
+ type: new principal.BlessingsId()._type
},
],
inStream: null,
@@ -481,13 +466,13 @@
inArgs: [{
name: 'peerBlessings',
doc: "",
- type: _type7
+ type: _type6
},
],
outArgs: [{
name: '',
doc: "",
- type: _type6
+ type: new principal.BlessingsId()._type
},
],
inStream: null,
@@ -519,7 +504,7 @@
outArgs: [{
name: '',
doc: "",
- type: _type6
+ type: new principal.BlessingsId()._type
},
],
inStream: null,
@@ -551,7 +536,7 @@
outArgs: [{
name: '',
doc: "",
- type: _type8
+ type: _type7
},
],
inStream: null,
@@ -593,7 +578,7 @@
outArgs: [{
name: '',
doc: "",
- type: _type7
+ type: _type6
},
],
inStream: null,
@@ -614,7 +599,7 @@
outArgs: [{
name: '',
doc: "",
- type: _type9
+ type: _type8
},
],
inStream: null,
@@ -629,13 +614,13 @@
inArgs: [{
name: 'toJoin',
doc: "",
- type: _type10
+ type: _type9
},
],
outArgs: [{
name: '',
doc: "",
- type: _type6
+ type: new principal.BlessingsId()._type
},
],
inStream: null,
diff --git a/src/gen-vdl/v.io/x/ref/services/wspr/internal/principal/index.js b/src/gen-vdl/v.io/x/ref/services/wspr/internal/principal/index.js
index a799f10..f11c056 100644
--- a/src/gen-vdl/v.io/x/ref/services/wspr/internal/principal/index.js
+++ b/src/gen-vdl/v.io/x/ref/services/wspr/internal/principal/index.js
@@ -16,16 +16,39 @@
// Types:
+var _typeBlessingsCacheAddMessage = new vdl.Type();
+var _typeBlessingsCacheDeleteMessage = new vdl.Type();
+var _typeBlessingsCacheMessage = new vdl.Type();
var _typeBlessingsHandle = new vdl.Type();
+var _typeBlessingsId = new vdl.Type();
var _typeJsBlessings = new vdl.Type();
+_typeBlessingsCacheAddMessage.kind = vdl.kind.STRUCT;
+_typeBlessingsCacheAddMessage.name = "v.io/x/ref/services/wspr/internal/principal.BlessingsCacheAddMessage";
+_typeBlessingsCacheAddMessage.fields = [{name: "CacheId", type: _typeBlessingsId}, {name: "Blessings", type: _typeJsBlessings}];
+_typeBlessingsCacheDeleteMessage.kind = vdl.kind.STRUCT;
+_typeBlessingsCacheDeleteMessage.name = "v.io/x/ref/services/wspr/internal/principal.BlessingsCacheDeleteMessage";
+_typeBlessingsCacheDeleteMessage.fields = [{name: "CacheId", type: _typeBlessingsId}, {name: "DeleteAfter", type: vdl.types.UINT32}];
+_typeBlessingsCacheMessage.kind = vdl.kind.UNION;
+_typeBlessingsCacheMessage.name = "v.io/x/ref/services/wspr/internal/principal.BlessingsCacheMessage";
+_typeBlessingsCacheMessage.fields = [{name: "Add", type: _typeBlessingsCacheAddMessage}, {name: "Delete", type: _typeBlessingsCacheDeleteMessage}];
_typeBlessingsHandle.kind = vdl.kind.INT32;
_typeBlessingsHandle.name = "v.io/x/ref/services/wspr/internal/principal.BlessingsHandle";
+_typeBlessingsId.kind = vdl.kind.UINT32;
+_typeBlessingsId.name = "v.io/x/ref/services/wspr/internal/principal.BlessingsId";
_typeJsBlessings.kind = vdl.kind.STRUCT;
_typeJsBlessings.name = "v.io/x/ref/services/wspr/internal/principal.JsBlessings";
_typeJsBlessings.fields = [{name: "Handle", type: _typeBlessingsHandle}, {name: "PublicKey", type: vdl.types.STRING}];
+_typeBlessingsCacheAddMessage.freeze();
+_typeBlessingsCacheDeleteMessage.freeze();
+_typeBlessingsCacheMessage.freeze();
_typeBlessingsHandle.freeze();
+_typeBlessingsId.freeze();
_typeJsBlessings.freeze();
+module.exports.BlessingsCacheAddMessage = (vdl.registry.lookupOrCreateConstructor(_typeBlessingsCacheAddMessage));
+module.exports.BlessingsCacheDeleteMessage = (vdl.registry.lookupOrCreateConstructor(_typeBlessingsCacheDeleteMessage));
+module.exports.BlessingsCacheMessage = (vdl.registry.lookupOrCreateConstructor(_typeBlessingsCacheMessage));
module.exports.BlessingsHandle = (vdl.registry.lookupOrCreateConstructor(_typeBlessingsHandle));
+module.exports.BlessingsId = (vdl.registry.lookupOrCreateConstructor(_typeBlessingsId));
module.exports.JsBlessings = (vdl.registry.lookupOrCreateConstructor(_typeJsBlessings));
@@ -44,6 +67,8 @@
// Services:
+
+
diff --git a/src/gen-vdl/v.io/x/ref/services/wspr/internal/rpc/server/index.js b/src/gen-vdl/v.io/x/ref/services/wspr/internal/rpc/server/index.js
index b27766f..4d2cfe6 100644
--- a/src/gen-vdl/v.io/x/ref/services/wspr/internal/rpc/server/index.js
+++ b/src/gen-vdl/v.io/x/ref/services/wspr/internal/rpc/server/index.js
@@ -28,7 +28,6 @@
var _type4 = new vdl.Type();
var _type5 = new vdl.Type();
var _type6 = new vdl.Type();
-var _type7 = new vdl.Type();
var _typeAuthReply = new vdl.Type();
var _typeCaveatValidationRequest = new vdl.Type();
var _typeCaveatValidationResponse = new vdl.Type();
@@ -52,12 +51,9 @@
_type5.kind = vdl.kind.LIST;
_type5.name = "";
_type5.elem = vdl.types.ERROR;
-_type6.kind = vdl.kind.OPTIONAL;
+_type6.kind = vdl.kind.LIST;
_type6.name = "";
-_type6.elem = new principal.JsBlessings()._type;
-_type7.kind = vdl.kind.LIST;
-_type7.name = "";
-_type7.elem = new signature.Interface()._type;
+_type6.elem = new signature.Interface()._type;
_typeAuthReply.kind = vdl.kind.STRUCT;
_typeAuthReply.name = "v.io/x/ref/services/wspr/internal/rpc/server.AuthReply";
_typeAuthReply.fields = [{name: "Err", type: vdl.types.ERROR}];
@@ -72,23 +68,22 @@
_typeContext.fields = [{name: "Language", type: vdl.types.STRING}];
_typeLookupReply.kind = vdl.kind.STRUCT;
_typeLookupReply.name = "v.io/x/ref/services/wspr/internal/rpc/server.LookupReply";
-_typeLookupReply.fields = [{name: "Handle", type: vdl.types.INT32}, {name: "HasAuthorizer", type: vdl.types.BOOL}, {name: "HasGlobber", type: vdl.types.BOOL}, {name: "Signature", type: _type7}, {name: "Err", type: vdl.types.ERROR}];
+_typeLookupReply.fields = [{name: "Handle", type: vdl.types.INT32}, {name: "HasAuthorizer", type: vdl.types.BOOL}, {name: "HasGlobber", type: vdl.types.BOOL}, {name: "Signature", type: _type6}, {name: "Err", type: vdl.types.ERROR}];
_typeSecurityCall.kind = vdl.kind.STRUCT;
_typeSecurityCall.name = "v.io/x/ref/services/wspr/internal/rpc/server.SecurityCall";
-_typeSecurityCall.fields = [{name: "Method", type: vdl.types.STRING}, {name: "Suffix", type: vdl.types.STRING}, {name: "MethodTags", type: _type1}, {name: "LocalBlessings", type: new principal.JsBlessings()._type}, {name: "LocalBlessingStrings", type: _type2}, {name: "RemoteBlessings", type: new principal.JsBlessings()._type}, {name: "RemoteBlessingStrings", type: _type2}, {name: "LocalEndpoint", type: vdl.types.STRING}, {name: "RemoteEndpoint", type: vdl.types.STRING}];
+_typeSecurityCall.fields = [{name: "Method", type: vdl.types.STRING}, {name: "Suffix", type: vdl.types.STRING}, {name: "MethodTags", type: _type1}, {name: "LocalBlessings", type: new principal.BlessingsId()._type}, {name: "LocalBlessingStrings", type: _type2}, {name: "RemoteBlessings", type: new principal.BlessingsId()._type}, {name: "RemoteBlessingStrings", type: _type2}, {name: "LocalEndpoint", type: vdl.types.STRING}, {name: "RemoteEndpoint", type: vdl.types.STRING}];
_typeServerRpcRequest.kind = vdl.kind.STRUCT;
_typeServerRpcRequest.name = "v.io/x/ref/services/wspr/internal/rpc/server.ServerRpcRequest";
_typeServerRpcRequest.fields = [{name: "ServerId", type: vdl.types.UINT32}, {name: "Handle", type: vdl.types.INT32}, {name: "Method", type: vdl.types.STRING}, {name: "Args", type: _type1}, {name: "Call", type: _typeServerRpcRequestCall}];
_typeServerRpcRequestCall.kind = vdl.kind.STRUCT;
_typeServerRpcRequestCall.name = "v.io/x/ref/services/wspr/internal/rpc/server.ServerRpcRequestCall";
-_typeServerRpcRequestCall.fields = [{name: "SecurityCall", type: _typeSecurityCall}, {name: "Deadline", type: new time.WireDeadline()._type}, {name: "Context", type: _typeContext}, {name: "TraceRequest", type: new vtrace.Request()._type}, {name: "GrantedBlessings", type: _type6}];
+_typeServerRpcRequestCall.fields = [{name: "SecurityCall", type: _typeSecurityCall}, {name: "Deadline", type: new time.WireDeadline()._type}, {name: "Context", type: _typeContext}, {name: "TraceRequest", type: new vtrace.Request()._type}, {name: "GrantedBlessings", type: new principal.BlessingsId()._type}];
_type1.freeze();
_type2.freeze();
_type3.freeze();
_type4.freeze();
_type5.freeze();
_type6.freeze();
-_type7.freeze();
_typeAuthReply.freeze();
_typeCaveatValidationRequest.freeze();
_typeCaveatValidationResponse.freeze();
diff --git a/src/proxy/index.js b/src/proxy/index.js
index cd2fe62..c0751cb 100644
--- a/src/proxy/index.js
+++ b/src/proxy/index.js
@@ -25,6 +25,7 @@
var ByteStreamMessageWriter = require('../vom/byte-stream-message-writer');
var ByteArrayMessageReader = require('../vom/byte-array-message-reader');
var TaskSequence = require('../lib/task-sequence');
+var promiseWhile = require('../lib/async-helper').promiseWhile;
// Cache the service signatures for one hour.
var SIGNATURE_CACHE_TTL = 3600 * 1000;
@@ -62,15 +63,17 @@
this.typeDecoder = new TypeDecoder();
this._messageReader = new ByteStreamMessageReader();
var proxy = this;
- this._messageReader.nextMessageType(this.typeDecoder).then(restartTypeReader);
-
- function restartTypeReader(typeId) {
- vlog.logger.error('The type stream should not have value message ' +
- typeId);
- return proxy.nextMessageType(proxy.typeDecoder).then(restartTypeReader)
- .catch(restartTypeReader);
- }
-
+ this._isOpen = true;
+ promiseWhile(function() {
+ return Promise.resolve(proxy._isOpen);
+ }, function() {
+ return proxy._messageReader.nextMessageType(proxy.typeDecoder)
+ .then(function(typeId) {
+ vlog.logger.error('Unexpected type id ' + typeId);
+ }).catch(function(err) {
+ vlog.logger.error('Type decoder failed' + err + ': ' + err.stack);
+ });
+ });
this.sequence = new TaskSequence();
EE.call(this);
}
@@ -140,6 +143,7 @@
var proxy = this;
return decoder.decode().then(function(message) {
message = unwrap(message);
+ // Type messages are handled by the proxy itself.
if (messageType === Incoming.TYPE_MESSAGE) {
proxy._messageReader.addBytes(message);
return;
@@ -250,6 +254,9 @@
Outgoing.TYPE_MESSAGE, null, 0);
};
+Proxy.prototype.cleanup = function() {
+ this._isOpen = false;
+};
/*
* Export the module
*/
diff --git a/src/proxy/message-type.js b/src/proxy/message-type.js
index b5cdc3c..33c6261 100644
--- a/src/proxy/message-type.js
+++ b/src/proxy/message-type.js
@@ -18,7 +18,7 @@
CANCEL: 17, // Cancel an ongoing JS initiated call.
CAVEAT_VALIDATION_RESPONSE: 21, // Response to a caveat validation request.
GRANTER_RESPONSE: 22, // Response from a granter
- TYPE_MESSAGE: 23,
+ TYPE_MESSAGE: 23, // A type message from javascript.
},
Incoming: {
INVOKE_REQUEST: 3, // Request to invoke a method on a JS server.
@@ -32,6 +32,7 @@
CAVEAT_VALIDATION_REQUEST: 8, // A request to validate a set of caveats
LOG_MESSAGE: 9, // A request to log a message.
GRANTER_REQUEST: 10, // A request to call a granter
- TYPE_MESSAGE: 12
+ BLESSINGS_CACHE_MESSAGE: 11, // A request to update the blessings cache
+ TYPE_MESSAGE: 12, // A type message from go.
}
};
diff --git a/src/proxy/nacl.js b/src/proxy/nacl.js
index 5143a93..c144b27 100644
--- a/src/proxy/nacl.js
+++ b/src/proxy/nacl.js
@@ -62,6 +62,7 @@
var self = this;
var defaultTimeout = 2000;
var deferred = new Deferred(cb);
+ this.cleanup();
extensionEventProxy.removeListener('crash', this.onCrash);
diff --git a/src/proxy/simple-handler.js b/src/proxy/simple-handler.js
deleted file mode 100644
index 6f9a8e3..0000000
--- a/src/proxy/simple-handler.js
+++ /dev/null
@@ -1,57 +0,0 @@
-// Copyright 2015 The Vanadium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-/**
- * @fileoverview A simple handler that resolves or rejects a promise
- * on a response from the proxy.
- * @private
- */
-var Incoming = require('./message-type').Incoming;
-var StreamHandler = require('./stream-handler');
-var vError = require('../gen-vdl/v.io/v23/verror');
-
-/**
- * An object that rejects/resolves a promise based on a response
- * from the proxy.
- * @constructor
- * @private
- * @param {Context} cxt
- * @param {Deferred} def the promise to resolve/reject
- * @param {ProxyConnection} proxy the proxy from which to dequeue the handler
- * @param {number} id the flow id of the message
- */
-var Handler = function(ctx, def, proxy, id) {
- this._ctx = ctx;
- this._proxy = proxy;
- this._def = def;
- this._id = id;
- if (def.stream) {
- this._streamHandler = new StreamHandler(ctx, def.stream);
- }
-
-};
-
-Handler.prototype.handleResponse = function(type, message) {
- // If there is a stream, let stream handler process it.
- if (this._streamHandler &&
- this._streamHandler.handleResponse(type, message)) {
- return;
- }
-
- switch (type) {
- case Incoming.FINAL_RESPONSE:
- this._def.resolve(message);
- break;
- case Incoming.ERROR_RESPONSE:
- this._def.reject(message);
- break;
- default:
- this._def.reject(
- new vError.InternalError(this._ctx,
- ['unknown response type ' + type]));
- }
- this._proxy.dequeue(this._id);
-};
-
-module.exports = Handler;
diff --git a/src/proxy/stream-handler.js b/src/proxy/stream-handler.js
index 84e4a14..672890c 100644
--- a/src/proxy/stream-handler.js
+++ b/src/proxy/stream-handler.js
@@ -6,9 +6,9 @@
var emitStreamError = require('../lib/emit-stream-error');
var vError = require('../gen-vdl/v.io/v23/verror');
var SharedContextKeys = require('../runtime/shared-context-keys');
-var Blessings = require('../security/blessings');
-var JsBlessings =
- require('../gen-vdl/v.io/x/ref/services/wspr/internal/principal').JsBlessings;
+var BlessingsId =
+ require('../gen-vdl/v.io/x/ref/services/wspr/internal/principal').BlessingsId;
+var runtimeFromContext = require('../runtime/runtime-from-context');
var TaskSequence = require('../lib/task-sequence');
var Promise = require('../lib/promise');
var vom = require('../vom');
@@ -59,12 +59,16 @@
}
var handler = this;
return vom.decode(data, false, this._typeDecoder).then(function(data) {
- if (data instanceof JsBlessings) {
- data = new Blessings(data.handle, data.publicKey,
- handler._controller);
- data.retain();
+ if (data instanceof BlessingsId) {
+ var runtime = runtimeFromContext(handler._ctx);
+ runtime.blessingsManager.blessingsFromId(data)
+ .then(function(blessings) {
+ blessings.retain();
+ handler._stream._queueRead(blessings);
+ });
+ } else {
+ handler._stream._queueRead(data);
}
- handler._stream._queueRead(data);
}, function(e) {
emitStreamError(handler._stream,
new vError.InternalError(
diff --git a/src/proxy/websocket.js b/src/proxy/websocket.js
index e5df1be..12a7e24 100644
--- a/src/proxy/websocket.js
+++ b/src/proxy/websocket.js
@@ -103,6 +103,7 @@
ProxyConnection.prototype.close = function(cb) {
var deferred = new Deferred(cb);
+ this.cleanup();
this.getWebSocket().then(close, function(err) {
// TODO(jasoncampbell): Better error handling around websocket connection
diff --git a/src/rpc/client.js b/src/rpc/client.js
index 8717da0..840b3ae 100644
--- a/src/rpc/client.js
+++ b/src/rpc/client.js
@@ -39,11 +39,12 @@
var SharedContextKeys = require('../runtime/shared-context-keys');
var vtrace = require('../vtrace');
var Blessings = require('../security/blessings');
-var JsBlessings =
- require('../gen-vdl/v.io/x/ref/services/wspr/internal/principal').JsBlessings;
var ByteArrayMessageWriter = require('../vom/byte-array-message-writer');
+var BlessingsId =
+ require('../gen-vdl/v.io/x/ref/services/wspr/internal/principal').BlessingsId;
var Encoder = require('../vom/encoder');
var TaskSequence = require('../lib/task-sequence');
+var runtimeFromContext = require('../runtime/runtime-from-context');
var vom = require('../vom');
var OutstandingRPC = function(ctx, options, cb) {
@@ -68,37 +69,34 @@
};
// Helper function to convert an out argument to the given type.
-function convertOutArg(arg, type, controller) {
- var canonOutArg = arg;
- var unwrappedArg = unwrap(arg);
- if (unwrappedArg instanceof JsBlessings) {
- var res =
- new Blessings(unwrappedArg.handle, unwrappedArg.publicKey, controller);
- res.retain();
- return res;
+function convertOutArg(ctx, arg, type, controller) {
+ if (arg instanceof BlessingsId) {
+ var runtime = runtimeFromContext(ctx);
+ return runtime.blessingsManager.blessingsFromId(arg)
+ .then(function(blessings) {
+ if (blessings) {
+ blessings.retain();
+ }
+ return blessings;
+ });
}
// There's no protection against bad out args if it's a JSValue.
// Otherwise, convert to the out arg type to ensure type correctness.
if (!type.equals(vdl.types.JSVALUE)) {
- canonOutArg = vdl.canonicalize.reduce(arg, type);
+ try {
+ return Promise.resolve(unwrap(vdl.canonicalize.reduce(arg, type)));
+ } catch(err) {
+ return Promise.reject(err);
+ }
}
- return unwrap(canonOutArg);
-}
-
-// Helper function to safely convert an out argument.
-// The returned error, if any is useful for a callback.
-function convertOutArgSafe(arg, type, controller) {
- try {
- return [undefined, convertOutArg(arg, type, controller)];
- } catch(err) {
- return [err, undefined];
- }
+ return Promise.resolve(unwrap(arg));
}
OutstandingRPC.prototype.start = function() {
this._id = this._proxy.nextId();
+ var ctx = this._ctx;
var self = this;
var cb;
@@ -111,25 +109,25 @@
cb = function convertToMultiArgs(err, results) { // jshint ignore:line
// If called from a deferred, the results are undefined.
- // Each out argument should also be unwrapped. (results was []any)
- results = results ? results.map(function(res, i) {
- var errOrArg = convertOutArgSafe(res, outArgTypes[i], self._controller);
- if (errOrArg[0] && !err) {
- err = errOrArg[0];
- }
- return errOrArg[1];
- }) : [];
+ if (err) {
+ origCb(err);
+ return;
+ }
- // TODO(alexfandrianto): Callbacks seem to be able to get both error and
- // results, but I think we want to limit it to one or the other.
- var resultsCopy = results.slice();
- resultsCopy.unshift(err);
- origCb.apply(null, resultsCopy);
+ // Each out argument should also be unwrapped. (results was []any)
+ results = results || [];
+ var resultPromises = results.map(function(res, i) {
+ return convertOutArg(ctx, res, outArgTypes[i], self._controller);
+ });
+ Promise.all(resultPromises)
+ .then(function(results) {
+ results.unshift(null);
+ origCb.apply(null, results);
+ }).catch(origCb);
};
}
var def = new Deferred(cb);
- var ctx = this._ctx;
if (!this._cb) {
// If we are using a promise, strip single args out of the arg array.
@@ -140,26 +138,29 @@
'Internal error: incorrectly formatted out args in client');
}
+
// Each out argument should also be unwrapped. (args was []any)
- var unwrappedArgs = args.map(function(outArg, i) {
- return convertOutArg(outArg, outArgTypes[i], self._controller);
+ var unwrappedArgPromises = args.map(function(outArg, i) {
+ return convertOutArg(ctx, outArg, outArgTypes[i], self._controller);
});
- // We expect:
- // 0 args - return; // NOT return [];
- // 1 args - return a; // NOT return [a];
- // 2 args - return [a, b] ;
- //
- // Convert the results from array style to the expected return style.
- // undefined, a, [a, b], [a, b, c] etc
- switch(unwrappedArgs.length) {
- case 0:
- return undefined;
- case 1:
- return unwrappedArgs[0];
- default:
- return unwrappedArgs;
- }
+ return Promise.all(unwrappedArgPromises).then(function(unwrappedArgs) {
+ // We expect:
+ // 0 args - return; // NOT return [];
+ // 1 args - return a; // NOT return [a];
+ // 2 args - return [a, b] ;
+ //
+ // Convert the results from array style to the expected return style.
+ // undefined, a, [a, b], [a, b, c] etc
+ switch(unwrappedArgs.length) {
+ case 0:
+ return undefined;
+ case 1:
+ return unwrappedArgs[0];
+ default:
+ return unwrappedArgs;
+ }
+ });
});
}
diff --git a/src/rpc/create-server-call.js b/src/rpc/create-server-call.js
new file mode 100644
index 0000000..616f787
--- /dev/null
+++ b/src/rpc/create-server-call.js
@@ -0,0 +1,63 @@
+// Copyright 2015 The Vanadium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+var createSecurityCall = require('../security/create-security-call');
+
+module.exports = createServerCall;
+
+/**
+ * Create a server call object. This exists so that we can resolve blessings
+ * before the user is given the object.
+ * @private
+ */
+function createServerCall(request, blessingsManager) {
+ var serverCall = new ServerCall();
+ if (request instanceof ServerCall) {
+ serverCall.securityCall = request.securityCall.clone();
+ serverCall.grantedBlessings = request.grantedBlessings;
+ return Promise.resolve(serverCall);
+ } else {
+ var promises = [];
+ promises.push(createSecurityCall(request.call.securityCall,
+ blessingsManager).then(function(securityCall) {
+ serverCall.securityCall = securityCall;
+ }));
+ if (request.call.grantedBlessings) {
+ promises.push(
+ blessingsManager.blessingsFromId(request.call.grantedBlessings)
+ .then(function(grantedBlessings) {
+ serverCall.grantedBlessings = grantedBlessings;
+ })
+ );
+ }
+ return Promise.all(promises).then(function() {
+ return serverCall;
+ });
+ }
+}
+
+/**
+ * @summary
+ * A ServerCall is a context.Context subclass that includes additional
+ * information about an ongoing server call.
+ * @description
+ * <p>Private Constructor, an instance of ServerCall is passed to every service
+ * method as the first argument.</p>
+ * @inner
+ * @constructor
+ *
+ * @property {module:vanadium.security~SecurityCall} securityCall The
+ * Security Call for the request.
+ *
+ * @property {module:vanadium.security~Blessings} grantedBlessings The
+ * blessings optionally granted to the server from the client through a
+ * granter.
+ *
+ * @property {*} methodTags The tags attached to the method,
+ * interface specification in VDL.
+ *
+ * @memberof module:vanadium.rpc
+ */
+function ServerCall() {
+}
diff --git a/src/rpc/granter-router.js b/src/rpc/granter-router.js
index dee6e7a..075d46c 100644
--- a/src/rpc/granter-router.js
+++ b/src/rpc/granter-router.js
@@ -12,7 +12,7 @@
var MessageType = require('../proxy/message-type');
var Incoming = MessageType.Incoming;
var Outgoing = MessageType.Outgoing;
-var SecurityCall = require('../security/call');
+var createSecurityCall = require('../security/create-security-call');
var InspectableFunction = require('../lib/inspectable-function');
var GranterResponse =
require('../gen-vdl/v.io/x/ref/services/wspr/internal/app').GranterResponse;
@@ -25,13 +25,14 @@
* grant requests.
* @private
*/
-function GranterRouter(proxy, rootCtx) {
+function GranterRouter(proxy, rootCtx, blessingsManager) {
proxy.addIncomingHandler(Incoming.GRANTER_REQUEST, this);
this._proxy = proxy;
this._rootCtx = rootCtx;
this.nextGranterId = 0;
this.activeGranters = {};
+ this._blessingsManager = blessingsManager;
}
/**
@@ -54,9 +55,10 @@
}
var router = this;
+ var granter;
return vom.decode(request).then(function(request) {
request = request.val;
- var granter = router.activeGranters[request.granterHandle];
+ granter = router.activeGranters[request.granterHandle];
if (!granter) {
// TODO(bjornick): Pass in context here so we can generate useful error
// messages
@@ -64,7 +66,11 @@
new verror.NoExistError(router._rootCtx, 'unknown granter'));
}
delete router.activeGranters[request.granterHandle];
- var securityCall = new SecurityCall(request.call, router._controller);
+ return createSecurityCall(request.call, router._blessingsManager);
+ }, function(e) {
+ return Promise.reject(
+ new verror.NoExistError(router._rootCtx, 'failed to decode message'));
+ }).then(function(securityCall) {
var ctx = router._rootCtx;
var inspectFn = new InspectableFunction(granter);
var resolve;
@@ -81,9 +87,6 @@
return resolve(res);
});
return promise;
- }, function(e) {
- return Promise.reject(
- new verror.NoExistError(router._rootCtx, 'failed to decode message'));
}).then(function(outBlessings) {
var result = new GranterResponse({blessings: outBlessings[0]._id});
var data = hexVom.encode(result);
diff --git a/src/rpc/server-call.js b/src/rpc/server-call.js
deleted file mode 100644
index ae9401e..0000000
--- a/src/rpc/server-call.js
+++ /dev/null
@@ -1,46 +0,0 @@
-// Copyright 2015 The Vanadium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-var SecurityCall = require('../security/call');
-var Blessings = require('../security/blessings');
-
-module.exports = ServerCall;
-
-/**
- * @summary
- * A ServerCall is a context.Context subclass that includes additional
- * information about an ongoing server call.
- * @description
- * <p>Private Constructor, an instance of ServerCall is passed to every service
- * method as the first argument.</p>
- * @inner
- * @constructor
- *
- * @property {module:vanadium.security~SecurityCall} securityCall The
- * Security Call for the request.
- *
- * @property {*} methodTags The tags attached to the method,
- * interface specification in VDL.
- *
- * @memberof module:vanadium.rpc
- */
-function ServerCall(request, controller) {
- if (!(this instanceof ServerCall)) {
- return new ServerCall(request, controller);
- }
-
- if (request instanceof ServerCall) {
- this.securityCall = request.securityCall.clone();
- this.grantedBlessings = request.grantedBlessings;
- } else {
- this.securityCall = new SecurityCall(request.call.securityCall,
- controller);
- if (request.call.grantedBlessings) {
- this.grantedBlessings = new Blessings(
- request.call.grantedBlessings.handle,
- request.call.grantedBlessings.publicKey,
- controller);
- }
- }
-}
diff --git a/src/rpc/server-router.js b/src/rpc/server-router.js
index 82ac8c4..6c4155c 100644
--- a/src/rpc/server-router.js
+++ b/src/rpc/server-router.js
@@ -16,8 +16,8 @@
var vlog = require('./../lib/vlog');
var StreamHandler = require('../proxy/stream-handler');
var verror = require('../gen-vdl/v.io/v23/verror');
-var SecurityCall = require('../security/call');
-var ServerCall = require('./server-call');
+var createSecurityCall = require('../security/create-security-call');
+var createServerCall = require('./create-server-call');
var vdl = require('../vdl');
var typeUtil = require('../vdl/type-util');
var Deferred = require('../lib/deferred');
@@ -37,8 +37,8 @@
var lib =
require('../gen-vdl/v.io/x/ref/services/wspr/internal/lib');
var Blessings = require('../security/blessings');
-var JsBlessings =
- require('../gen-vdl/v.io/x/ref/services/wspr/internal/principal').JsBlessings;
+var BlessingsId =
+ require('../gen-vdl/v.io/x/ref/services/wspr/internal/principal').BlessingsId;
var WireBlessings =
require('../gen-vdl/v.io/v23/security').WireBlessings;
var SharedContextKeys = require('../runtime/shared-context-keys');
@@ -52,7 +52,8 @@
* @constructor
* @private
*/
-var Router = function(proxy, appName, rootCtx, controller, caveatRegistry) {
+var Router = function(
+ proxy, appName, rootCtx, controller, caveatRegistry, blessingsManager) {
this._servers = {};
this._proxy = proxy;
this._streamMap = {};
@@ -62,6 +63,7 @@
this._caveatRegistry = caveatRegistry;
this._outstandingRequestForId = {};
this._controller = controller;
+ this._blessingsManager = blessingsManager;
proxy.addIncomingHandler(Incoming.INVOKE_REQUEST, this);
proxy.addIncomingHandler(Incoming.LOOKUP_REQUEST, this);
@@ -117,11 +119,15 @@
}
var router = this;
- var call;
- vom.decode(request).then(function(request) {
+ var decodedRequest;
+ vom.decode(request).catch(function(e) {
+ return Promise.reject(new verror.InternalError(router._rootCtx,
+ 'Failed to decode ', e));
+ }).then(function(req) {
+ decodedRequest = req;
var ctx = router._rootCtx.withValue(SharedContextKeys.LANG_KEY,
- request.context.language);
- var server = router._servers[request.serverId];
+ decodedRequest.context.language);
+ var server = router._servers[decodedRequest.serverId];
if (!server) {
var authReply = new AuthReply({
// TODO(bjornick): Use the real context
@@ -132,22 +138,20 @@
null, messageId);
return;
}
- call = new SecurityCall(request.call, router._controller);
-
- return server.handleAuthorization(request.handle, ctx, call);
- }, function(e) {
- return Promise.reject(new verror.InternalError(router._rootCtx,
- 'Failed to decode ', e));
+ return createSecurityCall(decodedRequest.call, router._blessingsManager)
+ .then(function(call) {
+ return server.handleAuthorization(decodedRequest.handle, ctx, call);
+ });
}).then(function() {
var authReply = new AuthReply({});
router._proxy.sendRequest(hexVom.encode(authReply),
Outgoing.AUTHORIZATION_RESPONSE, null, messageId);
}).catch(function(e) {
- var authReply = new AuthReply({
- err: ErrorConversion.fromNativeValue(e, router._appName,
- call.method)
- });
- router._proxy.sendRequest(hexVom.encode(authReply),
+ var errMsg = {
+ err: ErrorConversion.fromNativeValue(e, this._appName,
+ decodedRequest.call.method)
+ };
+ router._proxy.sendRequest(hexVom.encode(errMsg),
Outgoing.AUTHORIZATION_RESPONSE, null,
messageId);
});
@@ -179,24 +183,24 @@
};
Router.prototype.handleCaveatValidationRequest = function(messageId, request) {
- var resultPromises = new Array(request.cavs.length);
- var call = new SecurityCall(request.call);
- var ctx = this._rootCtx.withValue(SharedContextKeys.LANG_KEY,
- request.context.language);
- for (var i = 0; i < request.cavs.length; i++) {
- resultPromises[i] = this._validateChain(ctx, call, request.cavs[i]);
- }
- var self = this;
- Promise.all(resultPromises).then(function(results) {
- var response = new CaveatValidationResponse({
- results: results
+ var router = this;
+ createSecurityCall(request.call, this._blessingsManager)
+ .then(function(call) {
+ var ctx = router._rootCtx.withValue(SharedContextKeys.LANG_KEY,
+ request.context.language);
+ var resultPromises = request.cavs.map(function(cav) {
+ return router._validateChain(ctx, call, cav);
});
- self._proxy.sendRequest(hexVom.encode(response),
- Outgoing.CAVEAT_VALIDATION_RESPONSE, null,
- messageId);
+ return Promise.all(resultPromises).then(function(results) {
+ var response = new CaveatValidationResponse({
+ results: results
+ });
+ var data = hexVom.encode(response);
+ router._proxy.sendRequest(data, Outgoing.CAVEAT_VALIDATION_RESPONSE, null,
+ messageId);
+ });
}).catch(function(err) {
- vlog.logger.error(
- new Error('Unexpected error (all promises should resolve): ' + err));
+ throw new Error('Unexpected error (all promises should resolve): ' + err);
});
};
@@ -215,24 +219,24 @@
var self = this;
return server._handleLookup(request.suffix).then(function(value) {
- var signatureList = value.invoker.signature();
- var hasAuthorizer = (typeof value.authorizer === 'function');
- var hasGlobber = value.invoker.hasGlobber();
- var reply = new LookupReply({
- handle: value._handle,
- signature: signatureList,
- hasAuthorizer: hasAuthorizer,
- hasGlobber: hasGlobber
- });
- self._proxy.sendRequest(hexVom.encode(reply), Outgoing.LOOKUP_RESPONSE,
- null, messageId);
- }).catch(function(err) {
- var reply = new LookupReply({
- err: ErrorConversion.fromNativeValue(err, self._appName, '__Signature')
- });
- self._proxy.sendRequest(hexVom.encode(reply), Outgoing.LOOKUP_RESPONSE,
- null, messageId);
- });
+ var signatureList = value.invoker.signature();
+ var hasAuthorizer = (typeof value.authorizer === 'function');
+ var hasGlobber = value.invoker.hasGlobber();
+ var reply = new LookupReply({
+ handle: value._handle,
+ signature: signatureList,
+ hasAuthorizer: hasAuthorizer,
+ hasGlobber: hasGlobber
+ });
+ self._proxy.sendRequest(hexVom.encode(reply), Outgoing.LOOKUP_RESPONSE,
+ null, messageId);
+ }).catch(function(err) {
+ var reply = new LookupReply({
+ err: ErrorConversion.fromNativeValue(err, self._appName, '__Signature')
+ });
+ self._proxy.sendRequest(hexVom.encode(reply), Outgoing.LOOKUP_RESPONSE,
+ null, messageId);
+ });
};
/**
@@ -306,111 +310,118 @@
var ctx = this.createRPCContext(request);
var self = this;
var stream;
- var call = new ServerCall(request, this._controller);
- if (request.method === 'Glob__') {
- if (!invoker.hasGlobber()) {
- err = new Error('Glob is not implemented');
- self.sendResult(messageId, 'Glob__', null, err);
- return;
- }
- // Glob takes no streaming input and has GlobReply as output.
- stream = new Stream(messageId, this._proxy.senderPromise, false,
- null, naming.GlobReply.prototype._type);
- this._streamMap[messageId] = stream;
- this._contextMap[messageId] = ctx;
- this._outstandingRequestForId[messageId] = 0;
- this.incrementOutstandingRequestForId(messageId);
- var globPattern = typeUtil.unwrap(request.args[0]);
- this.handleGlobRequest(messageId, call.securityCall.suffix,
- server, new Glob(globPattern), ctx, call, invoker,
- completion);
- return;
- }
-
- function completion() {
- // There is no results to a glob method. Everything is sent back
- // through the stream.
- self.sendResult(messageId, methodName, null, undefined, 1);
- }
-
- // Find the method signature.
- var signature = invoker.signature();
- var methodSig;
- signature.forEach(function(ifaceSig) {
- ifaceSig.methods.forEach(function(method) {
- if (method.name === methodName) {
- methodSig = method;
+ createServerCall(request, this._blessingsManager).then(function(call) {
+ if (request.method === 'Glob__') {
+ if (!invoker.hasGlobber()) {
+ err = new Error('Glob is not implemented');
+ self.sendResult(messageId, 'Glob__', null, err);
+ return;
}
- });
- });
- if (methodSig === undefined) {
- err = new verror.NoExistError(
- call, 'Requested method', methodName, 'not found on');
- this.sendResult(messageId, methodName, null, err);
- return;
- }
-
- // Unwrap the RPC arguments sent to the JS server.
- var unwrappedArgs = request.args.map(function(arg, i) {
- // If an any type was expected, unwrapping is not needed.
- if (methodSig.inArgs[i].type.kind === vdl.kind.ANY) {
- return arg;
- }
- var unwrapped = typeUtil.unwrap(arg);
- if (unwrapped instanceof JsBlessings) {
- return new Blessings(unwrapped.handle, unwrapped.publicKey,
- self._controller);
- }
- return unwrapped;
- });
- var options = {
- methodName: methodName,
- args: unwrappedArgs,
- methodSig: methodSig,
- ctx: ctx,
- call: call,
- };
-
- this._contextMap[messageId] = options.ctx;
- if (methodIsStreaming(methodSig)) {
- var readType = (methodSig.inStream ? methodSig.inStream.type : null);
- var writeType = (methodSig.outStream ? methodSig.outStream.type : null);
- stream = new Stream(messageId, this._proxy.senderPromise, false, readType,
- writeType);
- this._streamMap[messageId] = stream;
- var rpc = new StreamHandler(options.ctx, stream);
- this._proxy.addIncomingStreamHandler(messageId, rpc);
- options.stream = stream;
- }
-
- // Invoke the method;
- this.invokeMethod(invoker, options, function(err, results) {
- if (err) {
- var stackTrace;
- if (err instanceof Error && err.stack !== undefined) {
- stackTrace = err.stack;
- }
- vlog.logger.debug('Requested method ' + methodName +
- ' threw an exception on invoke: ', err, stackTrace);
-
- // The error case has no results; only send the error.
- self.sendResult(messageId, methodName, undefined, err,
- methodSig.outArgs.length);
+ // Glob takes no streaming input and has GlobReply as output.
+ stream = new Stream(messageId, self._proxy.senderPromise, false,
+ null, naming.GlobReply.prototype._type);
+ self._streamMap[messageId] = stream;
+ self._contextMap[messageId] = ctx;
+ self._outstandingRequestForId[messageId] = 0;
+ self.incrementOutstandingRequestForId(messageId);
+ var globPattern = typeUtil.unwrap(request.args[0]);
+ self.handleGlobRequest(messageId, call.securityCall.suffix,
+ server, new Glob(globPattern), ctx, call, invoker,
+ completion);
return;
}
- // Has results; associate the types of the outArgs.
- var canonResults = results.map(function(result, i) {
- var t = methodSig.outArgs[i].type;
- if (t.equals(WireBlessings.prototype._type)) {
- return result;
- }
- return vdl.canonicalize.fill(result, t);
- });
- self.sendResult(messageId, methodName, canonResults, undefined,
- methodSig.outArgs.length);
- });
+ function completion() {
+ // There is no results to a glob method. Everything is sent back
+ // through the stream.
+ self.sendResult(messageId, methodName, null, undefined, 1);
+ }
+ // Find the method signature.
+ var signature = invoker.signature();
+ var methodSig;
+ signature.forEach(function(ifaceSig) {
+ ifaceSig.methods.forEach(function(method) {
+ if (method.name === methodName) {
+ methodSig = method;
+ }
+ });
+ });
+ if (methodSig === undefined) {
+ err = new verror.NoExistError(
+ call, 'Requested method', methodName, 'not found on');
+ self.sendResult(messageId, methodName, null, err);
+ return;
+ }
+
+ // Unwrap the RPC arguments sent to the JS server.
+ var unwrappedArgPromises = request.args.map(function(arg, i) {
+ // If an any type was expected, unwrapping is not needed.
+ if (methodSig.inArgs[i].type.kind === vdl.kind.ANY) {
+ return Promise.resolve(arg);
+ }
+ var unwrapped = typeUtil.unwrap(arg);
+ if (unwrapped instanceof BlessingsId) {
+ return self._blessingsManager.blessingsFromId(unwrapped);
+ }
+ return Promise.resolve(unwrapped);
+ });
+
+ return Promise.all(unwrappedArgPromises).then(function(unwrappedArgs) {
+ var options = {
+ methodName: methodName,
+ args: unwrappedArgs,
+ methodSig: methodSig,
+ ctx: ctx,
+ call: call,
+ };
+
+ self._contextMap[messageId] = options.ctx;
+ if (methodIsStreaming(methodSig)) {
+ var readType = (methodSig.inStream ? methodSig.inStream.type : null);
+ var writeType = (methodSig.outStream ? methodSig.outStream.type : null);
+ stream = new Stream(messageId, self._proxy.senderPromise, false,
+ readType, writeType);
+ self._streamMap[messageId] = stream;
+ var rpc = new StreamHandler(options.ctx, stream);
+ self._proxy.addIncomingStreamHandler(messageId, rpc);
+ options.stream = stream;
+ }
+
+ // Invoke the method;
+ self.invokeMethod(invoker, options, function(err, results) {
+ if (err) {
+ var stackTrace;
+ if (err instanceof Error && err.stack !== undefined) {
+ stackTrace = err.stack;
+ }
+ vlog.logger.debug('Requested method ' + methodName +
+ ' threw an exception on invoke: ', err, stackTrace);
+
+ // The error case has no results; only send the error.
+ self.sendResult(messageId, methodName, undefined, err,
+ methodSig.outArgs.length);
+ return;
+ }
+
+ // Has results; associate the types of the outArgs.
+ var canonResults = results.map(function(result, i) {
+ var t = methodSig.outArgs[i].type;
+ if (t.equals(WireBlessings.prototype._type)) {
+ if (!(result instanceof Blessings)) {
+ vlog.logger.error(
+ 'Encoding non-blessings value as wire blessings');
+ return null;
+ }
+ return result;
+ }
+ return vdl.canonicalize.fill(result, t);
+ });
+ self.sendResult(messageId, methodName, canonResults, undefined,
+ methodSig.outArgs.length);
+ });
+ });
+ });
};
/**
* Handles incoming requests from the server to invoke methods on registered
@@ -550,10 +561,13 @@
var suffix = namespaceUtil.join(name, child);
self.incrementOutstandingRequestForId(messageId);
- var subCall = new ServerCall(call);
- subCall.securityCall.suffix = suffix;
var nextInvoker;
- server._handleLookup(suffix).then(function(value) {
+ var subCall;
+ createServerCall(call, this._blessingsManager).then(function(servCall) {
+ subCall = servCall;
+ subCall.securityCall.suffix = suffix;
+ return server._handleLookup(suffix);
+ }).then(function(value) {
nextInvoker = value.invoker;
return server.handleAuthorization(value._handle, context,
subCall.securityCall);
diff --git a/src/runtime/index.js b/src/runtime/index.js
index 8f4a379..7c51044 100644
--- a/src/runtime/index.js
+++ b/src/runtime/index.js
@@ -23,6 +23,8 @@
var vtrace = require('../vtrace');
var Controller =
require('../gen-vdl/v.io/x/ref/services/wspr/internal/app').Controller;
+var BlessingsManager = require('../security/blessings-manager');
+var BlessingsRouter = require('../security/blessings-router');
module.exports = {
init: init
@@ -117,6 +119,9 @@
this._name = options.appName;
this._language = options.language;
this.caveatRegistry = new CaveatValidatorRegistry();
+ this.blessingsManager = new BlessingsManager(this._controller);
+ this._blessingsRouter = new BlessingsRouter(this._getProxyConnection(),
+ this.blessingsManager);
}
inherits(Runtime, EE);
@@ -249,7 +254,8 @@
this._name,
this.getContext(),
this._controller,
- this.caveatRegistry);
+ this.caveatRegistry,
+ this.blessingsManager);
}
return this._router;
};
@@ -263,7 +269,8 @@
if (!this._granterRouter) {
this._granterRouter = new GranterRouter(
this._getProxyConnection(),
- this.getContext());
+ this.getContext(),
+ this.blessingsManager);
}
return this._granterRouter;
};
diff --git a/src/security/access/permissions-authorizer.js b/src/security/access/permissions-authorizer.js
index c2a03ad..117b5db 100644
--- a/src/security/access/permissions-authorizer.js
+++ b/src/security/access/permissions-authorizer.js
@@ -12,7 +12,7 @@
var NoPermissionsError = vdlAccess.NoPermissionsError;
var Permissions = vdlAccess.Permissions;
-module.exports = authorizer;
+module.exports = permissionsAuthorizer;
var pkgPath = 'v.io/v23/security/access';
var MultipleTagsError = makeError(
pkgPath + '.errMultipleMethodTags',
@@ -38,7 +38,7 @@
* @return {module:vanadium.security.Authorize} An authorizer that applies
* the perms.
*/
-function authorizer(perms, type) {
+function permissionsAuthorizer(perms, type) {
// Force the Permissions to have the correct Permissions format.
var permissions = unwrap(new Permissions(perms));
@@ -70,4 +70,4 @@
}
return;
};
-}
\ No newline at end of file
+}
diff --git a/src/security/blessings-cache.js b/src/security/blessings-cache.js
new file mode 100644
index 0000000..e3b0444
--- /dev/null
+++ b/src/security/blessings-cache.js
@@ -0,0 +1,130 @@
+// Copyright 2015 The Vanadium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+var unwrap = require('../vdl/type-util').unwrap;
+var vlog = require('../lib/vlog');
+var Deferred = require('../lib/deferred');
+
+/**
+ * @fileoverview A cache of blessings, used in conjunction with the cache
+ * in WSPR (principal/cache.go) to reduce the number of times blessings must
+ * be sent across the wire.
+ * This is kept in sync with the WSPR cache.
+ * @private
+ */
+
+module.exports = BlessingsCache;
+
+/**
+ * @summary Cache of blessings received from WSPR.
+ * @description This cache is kept in sync with WSPR to reduce the
+ * number of times that blessings must be sent across the wire.
+ * @constructor
+ * @private
+ */
+function BlessingsCache() {
+ // Each entry has the following fields (which may or may not exist):
+ // - deferredBlessings: a deferred object whose promise resolves to the
+ // blessings
+ // - refCount: number of references to the blessings
+ // - deleteAfter: delete the entry after this number of blessings
+ this._entries = {};
+}
+
+/**
+ * @summary addBlessings adds blessings to the blessings cache.
+ * @param {wspr.internal.principal.BlessingsCacheAddMessage} addMessage
+ */
+BlessingsCache.prototype.addBlessings = function(addMessage) {
+ var id = this._unwrappedId(addMessage.cacheId);
+ var entry = this._getOrCreateEntry(id);
+ entry.deferredBlessings.resolve(addMessage.blessings);
+};
+
+/**
+ * @summary deleteBlessings removes blessings from the blessings cache.
+ * @param {wspr.internal.principal.BlessingsCacheAddMessage} addMessage
+ */
+BlessingsCache.prototype.deleteBlessings = function(deleteMessage) {
+ var id = this._unwrappedId(deleteMessage.cacheId);
+ var entry = this._getOrCreateEntry(id);
+ entry.deleteAfter = deleteMessage.deleteAfter;
+
+ this._deleteIfNoLongerNeeded(id);
+};
+
+/**
+ * @summary blessingsFromId looks up a blessing by id or waits for it if it
+ * has not been put in the cache yet
+ * @param {wspr.internal.principal.BlessingsId} blessingsId
+ */
+BlessingsCache.prototype.blessingsFromId = function(blessingsId) {
+ var id = unwrap(blessingsId);
+
+ if (typeof id !== 'number') {
+ throw new Error('Expected numeric blessings id');
+ }
+ if (id === 0) {
+ // Zero is not a valid id.
+ // TODO(bprosnitz) Replace this with null once we switch to full blessings
+ // objects. It is currently a number because there are no optional numbers
+ // now in VDL.
+ return Promise.resolve(null);
+ }
+
+ var entry = this._getOrCreateEntry(id);
+ var cache = this;
+ return entry.deferredBlessings.promise.then(function(blessings) {
+ cache._increaseRefCount(id);
+ cache._deleteIfNoLongerNeeded(id);
+ return blessings;
+ });
+};
+
+BlessingsCache.prototype._increaseRefCount = function(cacheId) {
+ var entry = this._entries[cacheId];
+ if (!entry) {
+ throw new Error('Unexpectedly got id of missing entry');
+ }
+ entry.refCount++;
+};
+
+BlessingsCache.prototype._deleteIfNoLongerNeeded = function(cacheId) {
+ var entry = this._entries[cacheId];
+ if (!entry) {
+ throw new Error('Entry unexpectedly not present');
+ }
+
+ if (entry.refCount >= entry.deleteAfter) {
+ if (entry.refCount > entry.deleteAfter) {
+ vlog.logger.warn('Got more references than expected');
+ }
+ if (entry.waiting) {
+ vlog.logger.warn(
+ 'There should not be anything waiting on entry to be deleted');
+ }
+ delete this._entries[cacheId];
+ }
+};
+
+BlessingsCache.prototype._getOrCreateEntry = function(cacheId) {
+ if (!this._entries[cacheId]) {
+ this._entries[cacheId] = {
+ refCount: 0,
+ deferredBlessings: new Deferred()
+ };
+ }
+ return this._entries[cacheId];
+};
+
+BlessingsCache.prototype._unwrappedId = function(cacheId) {
+ var id = unwrap(cacheId);
+ if (typeof id !== 'number') {
+ throw new Error('Got non-numeric id');
+ }
+ if (id <= 0) {
+ throw new Error('Unexpected non-positive id ' + id);
+ }
+ return id;
+};
diff --git a/src/security/blessings-manager.js b/src/security/blessings-manager.js
new file mode 100644
index 0000000..723b1d7
--- /dev/null
+++ b/src/security/blessings-manager.js
@@ -0,0 +1,49 @@
+// Copyright 2015 The Vanadium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+/**
+ * @fileoverview Manager of cache blessings. This differs from BlessingsCache
+ * because it converts JsBlessings to Blessings objects.
+ * TODO(bprosnitz) Remove this after switching to performing WireBlessings to
+ * Blessings conversion with native types.
+ * @private
+ */
+
+var BlessingsCache = require('../security/blessings-cache');
+var Blessings = require('../security/blessings');
+
+
+module.exports = BlessingsManager;
+
+/*
+ * TODO(bprosnitz) Replace this with just BlessingsCache after switching
+ * to using native type conversion with blessings.
+ */
+/*
+ * @summary Manager of blessings received from WSPR.
+ * @constructor
+ * @inner
+ */
+function BlessingsManager(controller) {
+ this._blessingsCache = new BlessingsCache();
+ this._controller = controller;
+}
+
+BlessingsManager.prototype.blessingsFromId = function(id) {
+ var controller = this._controller;
+ return this._blessingsCache.blessingsFromId(id).then(function(jsBless) {
+ if (!jsBless) {
+ return null;
+ }
+ return new Blessings(jsBless.handle, jsBless.publicKey, controller);
+ });
+};
+
+BlessingsManager.prototype.addBlessings = function(addMessage) {
+ return this._blessingsCache.addBlessings(addMessage);
+};
+
+BlessingsManager.prototype.deleteBlessings = function(deleteMessage) {
+ return this._blessingsCache.deleteBlessings(deleteMessage);
+};
diff --git a/src/security/blessings-router.js b/src/security/blessings-router.js
new file mode 100644
index 0000000..4254bf9
--- /dev/null
+++ b/src/security/blessings-router.js
@@ -0,0 +1,49 @@
+// Copyright 2015 The Vanadium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+/**
+ * @fileoveriew A router that handles incoming requests to update the state
+ * of the blessings cache.
+ * @private
+ */
+
+var vlog = require('./../lib/vlog');
+var Incoming = require('../proxy/message-type').Incoming;
+
+module.exports = BlessingsRouter;
+
+/**
+ * A router that handles incoming requests to update the state of the blessings
+ * cache.
+ * @constructor
+ * @private
+ */
+function BlessingsRouter(proxy, blessingsManager) {
+ this._blessingsManager = blessingsManager;
+
+ proxy.addIncomingHandler(Incoming.BLESSINGS_CACHE_MESSAGE, this);
+}
+
+BlessingsRouter.prototype.handleRequest = function(messageId, type, request) {
+ switch (type) {
+ case Incoming.BLESSINGS_CACHE_MESSAGE:
+ this.handleBlessingsCacheMessages(request);
+ return;
+ default:
+ vlog.logger.error('Unknown request type given to blessings router ' + type);
+ }
+};
+
+BlessingsRouter.prototype.handleBlessingsCacheMessages = function(messages) {
+ for (var i = 0; i < messages.length; i++) {
+ var message = messages[i];
+ if (message.hasOwnProperty('add')) {
+ this._blessingsManager.addBlessings(message.add);
+ } else if (message.hasOwnProperty('delete')) {
+ this._blessingsManager.deleteBlessings(message.delete);
+ } else {
+ vlog.logger.error('Unknown blessings cache message: ', message);
+ }
+ }
+};
diff --git a/src/security/blessingstore.js b/src/security/blessingstore.js
index 4ce7a31..ec74dd6 100644
--- a/src/security/blessingstore.js
+++ b/src/security/blessingstore.js
@@ -8,7 +8,7 @@
*/
var Deferred = require('../lib/deferred');
- var Blessings = require('./blessings');
+ var runtimeFromContext = require('../../src/runtime/runtime-from-context');
var verror = require('../gen-vdl/v.io/v23/verror');
module.exports = BlessingStore;
@@ -185,14 +185,17 @@
controller.blessingStorePeerBlessings(ctx)
.then(function(peerBlessings) {
var outPeerBlessings = new Map();
- peerBlessings.forEach(function(jsBlessings, pattern) {
- var blessingObj = new Blessings(
- jsBlessings.handle,
- jsBlessings.publicKey,
- controller);
- outPeerBlessings.set(pattern, blessingObj);
+ var promises = [];
+ peerBlessings.forEach(function(blessId, pattern) {
+ var runtime = runtimeFromContext(ctx);
+ promises.push(runtime.blessingsManager.blessingsFromId(blessId)
+ .then(function(blessingsObj) {
+ outPeerBlessings.set(pattern, blessingsObj);
+ }));
});
- def.resolve(outPeerBlessings);
+ return Promise.all(promises).then(function() {
+ def.resolve(outPeerBlessings);
+ });
}).catch(function(err) {
def.reject(err);
});
diff --git a/src/security/call.js b/src/security/call.js
deleted file mode 100644
index daf095f..0000000
--- a/src/security/call.js
+++ /dev/null
@@ -1,63 +0,0 @@
-// Copyright 2015 The Vanadium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-/**
- * @fileoverview A context passed to the authorizer
- * @private
- */
-var Blessings = require('./blessings.js');
-module.exports = Call;
-
-/**
- * @summary Call defines the state available for authorizing a principal.
- * @name SecurityCall
- * @property {string} method The method being invoked.
- * @property {string} suffix The object name suffix of the request.
- * @property {module:vanadium.security~Blessings} localBlessings The blessings
- * bound to the local end.
- * @property {string} localBlessingStrings The validated names for the local
- * end.
- * @property {module:vanadium.security~Blessings} remoteBlessings The blessings
- * bound to the remote end.
- * @property {string} remoteBlessingStrings The validated names for the remote
- * end.
- * @property {string} localEndpoint The endpoint string for the local end.
- * @property {string} remoteEndpoint The endpoint string for the remote end.
- * @inner
- * @memberof module:vanadium.security
- */
-function Call(call, controller) {
- this.method = call.method;
- this.suffix = call.suffix;
- // TODO(bjornick): Use the enums.
- this.methodTags = call.methodTags;
- this.localBlessings = new Blessings(call.localBlessings.handle,
- call.localBlessings.publicKey,
- controller);
- this.remoteBlessings = new Blessings(call.remoteBlessings.handle,
- call.remoteBlessings.publicKey,
- controller);
- if (call.grantedBlessings) {
- this.grantedBlessings = new Blessings(call.grantedBlessings.handle,
- call.grantedBlessings.publicKey,
- controller);
- }
- this.localBlessingStrings = call.localBlessingStrings;
- this.remoteBlessingStrings = call.remoteBlessingStrings;
- // TODO(bjornick): Create endpoints.
- this.localEndpoint = call.localEndpoint;
- this.remoteEndpoint = call.remoteEndpoint;
-}
-
-Call.prototype.clone = function() {
- var res = Object.create(this.constructor.prototype);
- Object.defineProperty(res, 'constructor', { value: this.constructor });
- for (var key in this) {
- if (!this.hasOwnProperty(key)) {
- continue;
- }
- res[key] = this[key];
- }
- return res;
-};
diff --git a/src/security/create-security-call.js b/src/security/create-security-call.js
new file mode 100644
index 0000000..8cdd467
--- /dev/null
+++ b/src/security/create-security-call.js
@@ -0,0 +1,74 @@
+// Copyright 2015 The Vanadium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+/**
+ * @fileoverview A security information passes to authorizer and validator.
+ * @private
+ */
+module.exports = createSecurityCall;
+
+/**
+ * Create a security call object. This exists so that we can resolve blessings
+ * before the user is given the object.
+ * @private
+ */
+function createSecurityCall(input, blessingsManager) {
+ var call = new Call();
+ call.method = input.method;
+ call.suffix = input.suffix;
+ call.methodTags = input.methodTags;
+ call.localBlessingStrings = input.localBlessingStrings;
+ call.remoteBlessingStrings = input.remoteBlessingStrings;
+ // TODO(bjornick): Create endpoints.
+ call.localEndpoint = input.localEndpoint;
+ call.remoteEndpoint = input.remoteEndpoint;
+
+ var promises = [];
+ promises.push(blessingsManager.blessingsFromId(input.localBlessings)
+ .then(function(localBlessings) {
+ call.localBlessings = localBlessings;
+ }));
+ promises.push(blessingsManager.blessingsFromId(input.remoteBlessings)
+ .then(function(remoteBlessings) {
+ call.remoteBlessings = remoteBlessings;
+ return call;
+ }));
+
+ return Promise.all(promises).then(function() {
+ return call;
+ });
+}
+
+/**
+ * @summary Call defines the state available for authorizing a principal.
+ * @name SecurityCall
+ * @property {string} method The method being invoked.
+ * @property {string} suffix The object name suffix of the request.
+ * @property {module:vanadium.security~Blessings} localBlessings The blessings
+ * bound to the local end.
+ * @property {string} localBlessingStrings The validated names for the local
+ * end.
+ * @property {module:vanadium.security~Blessings} remoteBlessings The blessings
+ * bound to the remote end.
+ * @property {string} remoteBlessingStrings The validated names for the remote
+ * end.
+ * @property {string} localEndpoint The endpoint string for the local end.
+ * @property {string} remoteEndpoint The endpoint string for the remote end.
+ * @inner
+ * @memberof module:vanadium.security
+ */
+function Call() {
+}
+
+Call.prototype.clone = function() {
+ var res = Object.create(this.constructor.prototype);
+ Object.defineProperty(res, 'constructor', { value: this.constructor });
+ for (var key in this) {
+ if (!this.hasOwnProperty(key)) {
+ continue;
+ }
+ res[key] = this[key];
+ }
+ return res;
+};
diff --git a/src/security/default-authorizer.js b/src/security/default-authorizer.js
index a16958f..6a952b4 100644
--- a/src/security/default-authorizer.js
+++ b/src/security/default-authorizer.js
@@ -5,9 +5,9 @@
var blessingMatches = require('./access/blessing-matching');
var vError = require('./../gen-vdl/v.io/v23/verror');
-module.exports = authorizer;
+module.exports = defaultAuthorizer;
-function authorizer(ctx, call, cb) {
+function defaultAuthorizer(ctx, call, cb) {
// If the remoteBlessings has a public key, and it refers to ourselves
// (i.e a self rpc), then we always authorize.
if (call.remoteBlessings.publicKey &&
diff --git a/src/security/principal.js b/src/security/principal.js
index bd69964..afc40cc 100644
--- a/src/security/principal.js
+++ b/src/security/principal.js
@@ -8,7 +8,6 @@
*/
var Deferred = require('../lib/deferred');
-var Blessings = require('./blessings');
var BlessingStore = require('./blessingstore');
var verror = require('../gen-vdl/v.io/v23/verror');
@@ -81,12 +80,9 @@
var caveats = args.slice(4);
- var controller = this._controller;
this._controller.bless(ctx, publicKey, blessings._id, extension, caveats)
- .then(function(res) {
- var publicKey = res[0];
- var handle = res[1];
- def.resolve(new Blessings(handle, publicKey, controller));
+ .then(function(blessings) {
+ def.resolve(blessings);
}).catch(function(err) {
def.reject(err);
});
@@ -121,14 +117,11 @@
var controller = this._controller;
controller.blessSelf(ctx, name, caveats)
- .then(function(res) {
- var publicKey = res[0];
- var handle = res[1];
- def.resolve(new Blessings(handle, publicKey, controller));
+ .then(function(blessings) {
+ def.resolve(blessings);
}).catch(function(err) {
def.reject(err);
});
-
return def.promise;
};
diff --git a/src/vom/type-encoder.js b/src/vom/type-encoder.js
index f951cb8..d74c5e8 100644
--- a/src/vom/type-encoder.js
+++ b/src/vom/type-encoder.js
@@ -27,17 +27,18 @@
* @constructor
* @param {module:vanadium.vom.ByteArrayMessageWriter} messageWriter The message
* writer to write to.
- * @param {function} flusher A function that will be called every time a type
- * message has been written.
+ * @param {function} flush A function that will be called every time a type
+ * message has been written. An example is to write copy the bytes in
+ * messageWriter to the wire every time a type message is written.
* @memberof module:vanadium.vom
*/
-function TypeEncoder(messageWriter, flusher) {
+function TypeEncoder(messageWriter, flush) {
this._typeIds = {};
// TODO(bjornick): Use the vdl output after we fix:
// https://github.com/veyron/release-issues/issues/1109
this._nextId = unwrap(wiretype.WireIdFirstUserType);
this._messageWriter = messageWriter;
- this._flusher = flusher;
+ this._flush = flush;
}
/**
@@ -71,8 +72,8 @@
var typeId = this._nextId++;
this._typeIds[stringifiedType] = typeId;
this._encodeWireType(type, typeId);
- if (this._flusher) {
- this._flusher();
+ if (this._flush) {
+ this._flush();
}
return typeId;
};
diff --git a/test/integration/serve.js b/test/integration/serve.js
index 40b8d1c..9d67350 100644
--- a/test/integration/serve.js
+++ b/test/integration/serve.js
@@ -75,7 +75,6 @@
return callback(err, basicRes);
}
- console.log('finished with ' + err);
var ctx = runtime.getContext();
waitUntilResolve();
diff --git a/test/integration/test-authorizer.js b/test/integration/test-authorizer.js
index 895ead4..b8ff575 100644
--- a/test/integration/test-authorizer.js
+++ b/test/integration/test-authorizer.js
@@ -56,10 +56,9 @@
var ctx = res.runtime.getContext();
client.bindTo(ctx, 'authorizerTestService/auth').then(function(service) {
service.call(ctx, 'foo').then(function(value) {
- assert.error(new Error('call should not have succeeded' + value));
+ assert.error(new Error('call should not have succeeded. res:' + value));
res.end(assert);
}).catch(function(err) {
- // We expect to get to the error case.
assert.ok(err);
res.end(assert);
});
diff --git a/test/ui/src/test/java/io/v/webdriver/VanadiumUITestBase.java b/test/ui/src/test/java/io/v/webdriver/VanadiumUITestBase.java
index 129bf3e..6c5cee5 100644
--- a/test/ui/src/test/java/io/v/webdriver/VanadiumUITestBase.java
+++ b/test/ui/src/test/java/io/v/webdriver/VanadiumUITestBase.java
@@ -11,6 +11,7 @@
import org.openqa.selenium.chrome.ChromeDriver;
import org.openqa.selenium.chrome.ChromeDriverService;
+import io.v.webdriver.Util;
import io.v.webdriver.htmlreport.HTMLReportData;
import io.v.webdriver.commonpages.ChromeSignInPage;
import io.v.webdriver.commonpages.ExtensionInstallationPage;
@@ -143,5 +144,8 @@
// Check Vanadium extension option page.
ExtensionOptionPage extensionOptionPage = new ExtensionOptionPage(driver, reportData);
extensionOptionPage.go();
+
+ // Wait a little bit to allow the extension to get ready.
+ Util.sleep(5000);
}
}
diff --git a/test/unit/test-blessings-cache.js b/test/unit/test-blessings-cache.js
new file mode 100644
index 0000000..1999e3c
--- /dev/null
+++ b/test/unit/test-blessings-cache.js
@@ -0,0 +1,337 @@
+// Copyright 2015 The Vanadium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+var test = require('prova');
+var BlessingsCache = require('../../src/security/blessings-cache');
+var principal =
+ require('../../src/gen-vdl/v.io/x/ref/services/wspr/internal/principal');
+
+test('Blessing cache - add before use', function(t) {
+ var blessingsA = {
+ publicKey: 'A'
+ };
+ var messages = [
+ {
+ type: 'add',
+ value: {
+ cacheId: 1,
+ blessings: blessingsA
+ }
+ },
+ {
+ type: 'blessingsFromId',
+ cacheId: 1,
+ expected: blessingsA
+ }
+ ];
+
+ testCache(t, messages);
+});
+
+test('Blessing cache - add after use', function(t) {
+ var blessingsA = {
+ publicKey: 'A'
+ };
+ var messages = [
+ {
+ type: 'blessingsFromId',
+ cacheId: 1,
+ expected: blessingsA
+ },
+ {
+ type: 'add',
+ value: {
+ cacheId: 1,
+ blessings: blessingsA
+ },
+ dontWaitPrevious: true
+ }
+ ];
+
+ testCache(t, messages);
+});
+
+test('Blessing cache - delete after add', function(t) {
+ var blessingsA = {
+ publicKey: 'A'
+ };
+ var messages = [
+ {
+ type: 'add',
+ value: {
+ cacheId: 1,
+ blessings: blessingsA
+ }
+ },
+ {
+ type: 'delete',
+ value: {
+ cacheId: 1,
+ deleteAfter: 0
+ },
+ },
+ {
+ type: 'confirmDelete',
+ cacheId: 1
+ }
+ ];
+
+ testCache(t, messages);
+});
+
+test('Blessing cache - reference counting delete', function(t) {
+ var blessingsA = {
+ publicKey: 'A'
+ };
+ var messages = [
+ {
+ type: 'add',
+ value: {
+ cacheId: 1,
+ blessings: blessingsA
+ }
+ },
+ {
+ type: 'delete',
+ value: {
+ cacheId: 1,
+ deleteAfter: 2
+ },
+ },
+ {
+ type: 'blessingsFromId',
+ cacheId: 1,
+ expected: blessingsA
+ },
+ {
+ type: 'blessingsFromId',
+ cacheId: 1,
+ expected: blessingsA
+ },
+ {
+ type: 'confirmDelete',
+ cacheId: 1
+ }
+ ];
+
+ testCache(t, messages);
+});
+
+test('Blessing cache - add after delete', function(t) {
+ var blessingsA = {
+ publicKey: 'A'
+ };
+ var messages = [
+ {
+ type: 'delete',
+ value: {
+ cacheId: 1,
+ deleteAfter: 1
+ },
+ },
+ {
+ type: 'add',
+ value: {
+ cacheId: 1,
+ blessings: blessingsA
+ }
+ },
+ {
+ type: 'blessingsFromId',
+ cacheId: 1,
+ expected: blessingsA
+ },
+ {
+ type: 'confirmDelete',
+ cacheId: 1
+ }
+ ];
+
+ testCache(t, messages);
+});
+
+test('Blessing cache - multiple entries', function(t) {
+ var blessingsA = {
+ publicKey: 'A'
+ };
+ var blessingsB = {
+ publicKey: 'B'
+ };
+ var blessingsC = {
+ publicKey: 'C'
+ };
+ var messages = [
+ {
+ type: 'add',
+ value: {
+ cacheId: 1,
+ blessings: blessingsA
+ }
+ },
+ {
+ type: 'add',
+ value: {
+ cacheId: 2,
+ blessings: blessingsB
+ }
+ },
+ {
+ type: 'blessingsFromId',
+ cacheId: 2,
+ expected: blessingsB
+ },
+ {
+ type: 'blessingsFromId',
+ cacheId: 1,
+ expected: blessingsA
+ },
+ {
+ type: 'delete',
+ value: {
+ cacheId: 1,
+ deleteAfter: 1
+ },
+ },
+ {
+ type: 'confirmDelete',
+ cacheId: 1
+ },
+ {
+ type: 'add',
+ value: {
+ cacheId: 3,
+ blessings: blessingsC
+ }
+ },
+ {
+ type: 'delete',
+ value: {
+ cacheId: 2,
+ deleteAfter: 3
+ },
+ },
+ {
+ type: 'blessingsFromId',
+ cacheId: 2,
+ expected: blessingsB
+ },
+ {
+ type: 'blessingsFromId',
+ cacheId: 3,
+ expected: blessingsC
+ },
+ {
+ type: 'delete',
+ value: {
+ cacheId: 3,
+ deleteAfter: 1
+ },
+ },
+ {
+ type: 'confirmDelete',
+ cacheId: 3
+ },
+ {
+ type: 'blessingsFromId',
+ cacheId: 2,
+ expected: blessingsB
+ },
+ {
+ type: 'confirmDelete',
+ cacheId: 2
+ }
+ ];
+
+ testCache(t, messages);
+});
+
+test('Blessing cache handles typed BlessingsId objects', function(t) {
+ var blessingsA = {
+ publicKey: 'A'
+ };
+ var messages = [
+ {
+ type: 'add',
+ value: {
+ cacheId: 1,
+ blessings: blessingsA
+ }
+ },
+ {
+ type: 'blessingsFromId',
+ cacheId: new principal.BlessingsId(1),
+ expected: blessingsA
+ }
+ ];
+
+ testCache(t, messages);
+});
+
+test('Blessing cache handles zero blessing id', function(t) {
+ var messages = [
+ {
+ type: 'blessingsFromId',
+ cacheId: new principal.BlessingsId(0),
+ expected: null
+ }
+ ];
+
+ testCache(t, messages);
+});
+
+/**
+ * Tests the cache by handling a sequence of messages.
+ * @private
+ */
+function testCache(t, messages) {
+ var cache = new BlessingsCache();
+ var promises = [];
+ messages.forEach(function(message, index) {
+ // Wait for the previous messages to finish unless dontWaitPrevious is
+ // specified.
+ var preCondPromise = Promise.all(promises);
+ if (message.dontWaitPrevious) {
+ preCondPromise = Promise.resolve();
+ }
+
+ var result = preCondPromise.then(function() {
+ return handleCacheTestMessage(t, cache, message, index);
+ }).catch(function(err) {
+ t.fail('Error in message ' + index + ': ' + err);
+ });
+ promises.push(result);
+ });
+
+ // Wait for all promises to complete.
+ Promise.all(promises).then(function() {
+ t.end();
+ }).catch(function(err) {
+ t.end(err);
+ });
+}
+
+function handleCacheTestMessage(t, cache, message, index) {
+ if (message.type === 'add') {
+ var addMsg = new principal.BlessingsCacheAddMessage(message.value);
+ return cache.addBlessings(addMsg);
+ } else if (message.type === 'delete') {
+ var delMsg = new principal.BlessingsCacheDeleteMessage(message.value);
+ return cache.deleteBlessings(delMsg);
+ } else if (message.type === 'confirmDelete') {
+ t.ok(cache._entries, 'Entries table should exist');
+ t.notOk(message.cacheId in cache._entries,
+ 'Cache entry not deleted correctly on message ' + index);
+ } else if (message.type === 'blessingsFromId') {
+ return cache.blessingsFromId(message.cacheId).then(function(blessings) {
+ var expected = null;
+ if (message.expected !== null) {
+ expected = new principal.JsBlessings(message.expected);
+ }
+ t.deepEqual(blessings, expected,
+ 'Should get expected blessings on message ' + index);
+ });
+ } else {
+ throw new Error('unknown message type');
+ }
+}
diff --git a/test/unit/test-caveat-validator-registry.js b/test/unit/test-caveat-validator-registry.js
index 67fbf9d..f43a275 100644
--- a/test/unit/test-caveat-validator-registry.js
+++ b/test/unit/test-caveat-validator-registry.js
@@ -6,13 +6,12 @@
var CaveatValidatorRegistry =
require('../../src/security/caveat-validator-registry');
var context = require('../../src/context');
-var SecurityCall = require('../../src/security/call');
var caveats = require('../../src/security/caveats');
var testCaveats = require('../vdl-out/javascript-test/security/caveat');
function getMockSecurityCall() {
- return new SecurityCall({
+ return {
method: '',
suffix: '',
methodTags: [],
@@ -28,9 +27,7 @@
remoteBlessingStrings: [],
localEndpoint: '',
remoteEndpoint: ''
- },
- null, // controller
- context.Context());
+ };
}
diff --git a/test/unit/test-standard-caveat-validators.js b/test/unit/test-standard-caveat-validators.js
index 0285090..41e545e 100644
--- a/test/unit/test-standard-caveat-validators.js
+++ b/test/unit/test-standard-caveat-validators.js
@@ -8,12 +8,11 @@
var caveats = require('../../src/security/caveats');
var vdlSecurity = require('../../src/gen-vdl/v.io/v23/security');
var context = require('../../src/context');
-var SecurityCall = require('../../src/security/call');
var Time = require('../../src/gen-vdl/v.io/v23/vdlroot/time').Time;
var vdl = require('../../src/vdl');
function getMockSecurityCall() {
- return new SecurityCall({
+ return {
method: 'aMethod', // only field currently used
suffix: '',
methodTags: [],
@@ -29,9 +28,7 @@
remoteBlessingStrings: [],
localEndpoint: '',
remoteEndpoint: ''
- },
- null, // controller
- context.Context());
+ };
}
function assertValidation(t, cavType, val, cb) {