Adam Ierymenko 8 年之前
父节点
当前提交
1c04cc0485
共有 1 个文件被更改,包括 267 次插入19 次删除
  1. 267 19
      controller/controller-api-model.js

+ 267 - 19
controller/controller-api-model.js

@@ -26,18 +26,6 @@
 
 'use strict';
 
-/**
- * Goes through a rule set array and makes sure it's valid, returning a canonicalized version
- *
- * @param {array[object]} rules Array of ZeroTier rules
- * @return New array of canonicalized rules
- * @throws {Error} Rule set is invalid
- */
-function formatRuleSetArray(rules)
-{
-}
-exports.formatRuleSetArray = formatRuleSetArray;
-
 /**
  * @param {string} IP with optional /netmask|port section
  * @return 4, 6, or 0 if invalid
@@ -103,6 +91,135 @@ function formatZeroTierIdentifier(x,l)
 };
 exports.formatZeroTierIdentifier = formatZeroTierIdentifier;
 
+/**
+ * Goes through a rule set array and makes sure it's valid, returning a canonicalized version
+ *
+ * @param {array[object]} rules Array of ZeroTier rules
+ * @return New array of canonicalized rules
+ * @throws {Error} Rule set is invalid
+ */
+function formatRuleSetArray(rules)
+{
+	let r = [];
+	if ((rules)&&(Array.isArray(rules))) {
+		for(let a=0;a<rules.length;++a) {
+			let rule = rules[a];
+			if (rule.type) {
+				let nr = null;
+				switch(rule.type) {
+					case 'ACTION_DROP':
+					case 'ACTION_ACCEPT':
+					case 'ACTION_BREAK':
+						break;
+					case 'ACTION_TEE':
+					case 'ACTION_WATCH':
+						nr = { 'type': rule['type'],'not': !!rule['not'],'or': !!rule['or'] };
+						nr.address = formatZeroTierIdentifier(rule.address,10);
+						nr.flags = parseInt(rule.flags)||0;
+						nr['length'] = parseInt(rule['length'])||0;
+						break;
+					case 'ACTION_REDIRECT':
+						nr = { 'type': rule['type'],'not': !!rule['not'],'or': !!rule['or'] };
+						nr.address = formatZeroTierIdentifier(rule.address,10);
+						nr.flags = parseInt(rule.flags)||0;
+						break;
+					case 'MATCH_SOURCE_ZEROTIER_ADDRESS':
+					case 'MATCH_DEST_ZEROTIER_ADDRESS':
+						nr = { 'type': rule['type'],'not': !!rule['not'],'or': !!rule['or'] };
+						nr.zt = formatZeroTierIdentifier(rule.zt,10);
+						break;
+					case 'MATCH_VLAN_ID':
+						nr = { 'type': rule['type'],'not': !!rule['not'],'or': !!rule['or'] };
+						nr.vlanId = parseInt(rule.vlanId)||0;
+						break;
+					case 'MATCH_VLAN_PCP':
+						nr = { 'type': rule['type'],'not': !!rule['not'],'or': !!rule['or'] };
+						nr.vlanPcp = parseInt(rule.vlanPcp)||0;
+						break;
+					case 'MATCH_VLAN_DEI':
+						nr = { 'type': rule['type'],'not': !!rule['not'],'or': !!rule['or'] };
+						nr.vlanDei = parseInt(rule.vlanDei)||0;
+						break;
+					case 'MATCH_MAC_SOURCE':
+					case 'MATCH_MAC_DEST':
+						nr = { 'type': rule['type'],'not': !!rule['not'],'or': !!rule['or'] };
+						nr.mac = formatZeroTierIdentifier(rule.mac,12);
+						nr.mac = (nr.mac.substr(0,2)+':'+nr.mac.substr(2,2)+':'+nr.mac.substr(4,2)+':'+nr.mac.substr(6,2)+':'+nr.mac.substr(8,2)+':'+nr.mac.substr(10,2));
+						break;
+					case 'MATCH_IPV4_SOURCE':
+					case 'MATCH_IPV4_DEST':
+						if (ipClassify(rule.ip) !== 4)
+							continue;
+						nr = { 'type': rule['type'],'not': !!rule['not'],'or': !!rule['or'] };
+						nr.ip = rule.ip;
+						break;
+					case 'MATCH_IPV6_SOURCE':
+					case 'MATCH_IPV6_DEST':
+						if (ipClassify(rule.ip) !== 6)
+							continue;
+						nr = { 'type': rule['type'],'not': !!rule['not'],'or': !!rule['or'] };
+						nr.ip = rule.ip;
+						break;
+					case 'MATCH_IP_TOS':
+						nr = { 'type': rule['type'],'not': !!rule['not'],'or': !!rule['or'] };
+						nr.mask = parseInt(rule.mask)||0;
+						nr.start = parseInt(rule.start)||0;
+						nr.end = parseInt(rule.end)||0;
+						break;
+					case 'MATCH_IP_PROTOCOL':
+						nr = { 'type': rule['type'],'not': !!rule['not'],'or': !!rule['or'] };
+						nr.ipProtocol = parseInt(rule.ipProtocol)||0;
+						break;
+					case 'MATCH_ETHERTYPE':
+						nr = { 'type': rule['type'],'not': !!rule['not'],'or': !!rule['or'] };
+						nr.etherType = parseInt(rule.etherType)||0;
+						break;
+					case 'MATCH_ICMP':
+						nr = { 'type': rule['type'],'not': !!rule['not'],'or': !!rule['or'] };
+						nr.icmpType = parseInt(rule.icmpType)||0;
+						nr.icmpCode = ('icmpCode' in rule) ? ((rule.icmpCode === null) ? null : (parseInt(rule.icmpCode)||0)) : null;
+						break;
+					case 'MATCH_IP_SOURCE_PORT_RANGE':
+					case 'MATCH_IP_DEST_PORT_RANGE':
+						nr = { 'type': rule['type'],'not': !!rule['not'],'or': !!rule['or'] };
+						nr.start = parseInt(rule.start)||0;
+						nr.end = parseInt(rule.end)||0;
+						break;
+					case 'MATCH_CHARACTERISTICS':
+						nr = { 'type': rule['type'],'not': !!rule['not'],'or': !!rule['or'] };
+						nr.mask = formatZeroTierIdentifier(rule.mask,16); // hex number, so this will work
+						break;
+					case 'MATCH_FRAME_SIZE_RANGE':
+						nr = { 'type': rule['type'],'not': !!rule['not'],'or': !!rule['or'] };
+						nr.start = parseInt(rule.start)||0;
+						nr.end = parseInt(rule.end)||0;
+						break;
+					case 'MATCH_RANDOM':
+						nr = { 'type': rule['type'],'not': !!rule['not'],'or': !!rule['or'] };
+						nr.probability = parseInt(rule.probability)||0;
+						break;
+					case 'MATCH_TAGS_DIFFERENCE':
+					case 'MATCH_TAGS_BITWISE_AND':
+					case 'MATCH_TAGS_BITWISE_OR':
+					case 'MATCH_TAGS_BITWISE_XOR':
+					case 'MATCH_TAGS_EQUAL':
+					case 'MATCH_TAG_SENDER':
+					case 'MATCH_TAG_RECEIVER':
+						nr = { 'type': rule['type'],'not': !!rule['not'],'or': !!rule['or'] };
+						nr.id = parseInt(rule.id)||0;
+						nr.value = parseInt(rule.value)||0;
+						break;
+					default:
+						continue;
+				}
+				r.push(nr);
+			}
+		}
+	}
+	return r;
+}
+exports.formatRuleSetArray = formatRuleSetArray;
+
 // Internal container classes
 class _V4AssignMode
 {
@@ -115,7 +232,7 @@ class _V4AssignMode
 };
 class _v6AssignMode
 {
-	get ['6plane'] { return (this._6plane)||false; }
+	get ['6plane']() { return (this._6plane)||false; }
 	set ['6plane'](b) { this._6plane = !!b; }
 	get zt() { return (this._zt)||false; }
 	set zt(b) { this._zt = !!b; }
@@ -192,7 +309,7 @@ class Network
 		return ca;
 	}
 
-	get ipAssignmentPools() return { this._ipAssignmentPools; }
+	get ipAssignmentPools() { return this._ipAssignmentPools; }
 	set ipAssignmentPools(ipp)
 	{
 		let pa = [];
@@ -218,7 +335,7 @@ class Network
 		return pa;
 	}
 
-	get multicastLimit() return { this._multicastLimit; }
+	get multicastLimit() { return this._multicastLimit; }
 	set multicastLimit(n)
 	{
 		try {
@@ -230,7 +347,7 @@ class Network
 		return this._multicastLimit;
 	}
 
-	get routes() return { this._routes; }
+	get routes() { return this._routes; }
 	set routes(r)
 	{
 		let ra = [];
@@ -254,7 +371,7 @@ class Network
 		return ra;
 	}
 
-	get tags() return { this._tags; }
+	get tags() { return this._tags; }
 	set tags(t)
 	{
 		let ta = [];
@@ -283,7 +400,7 @@ class Network
 		return ta;
 	}
 
-	get v4AssignMode() return { this._v4AssignMode; }
+	get v4AssignMode() { return this._v4AssignMode; }
 	set v4AssignMode(m)
 	{
 		if ((m)&&(typeof m === 'object')&&(!Array.isArray(m))) {
@@ -295,7 +412,7 @@ class Network
 		}
 	}
 
-	get v6AssignMode() return { this._v6AssignMode; }
+	get v6AssignMode() { return this._v6AssignMode; }
 	set v6AssignMode(m)
 	{
 		if ((m)&&(typeof m === 'object')&&(!Array.isArray(m))) {
@@ -495,6 +612,20 @@ class Member
 	get capabilities() { return this._capabilities; }
 	set capabilities(c)
 	{
+		let caps = {};
+		let ca = [];
+		if ((c)&&(Array.isArray(c))) {
+			for(let a=0;a<c.length;++a) {
+				let capId = parseInt(c[a])||0;
+				if ((capId >= 0)&&(capId <= 0xffffffff)&&(!caps[capId])) {
+					caps[capId] = true;
+					ca.push(capId);
+				}
+			}
+		}
+		ca.sort();
+		this._capabilities = ca;
+		return ca;
 	}
 
 	get identity() { return this._identity; }
@@ -508,6 +639,17 @@ class Member
 	get ipAssignments() { return this._ipAssignments; }
 	set ipAssignments(ipa)
 	{
+		let ips = {};
+		if ((ipa)&&(Array.isArray(ipa))) {
+			for(let a=0;a<ipa.length;++a) {
+				let ip = ipa[a];
+				if (ipClassify(ip) > 0)
+					ips[ip] = true;
+			}
+		}
+		this._ipAssignments = Object.keys(ips);
+		this._ipAssignments.sort();
+		return this._ipAssignments;
 	}
 
 	get noAutoAssignIps() { return this._noAutoAssignIps; }
@@ -516,6 +658,73 @@ class Member
 	get tags() { return this._tags; }
 	set tags(t)
 	{
+		let ta = [];
+		let pairs = {};
+		if ((t)&&(Array.isArray(t))) {
+			for(let a=0;a<t.length;++a) {
+				let tag = a[t];
+				if ((tag)&&(Array.isArray(tag))&&(tag.length === 2)) {
+					let tagId = parseInt(tag[0])||0;
+					let tagValue = parseInt(tag[1])||0;
+					let pk = tagId.toString()+'_'+tagValue.toString();
+					if ((tagId >= 0)&&(tagId <= 0xffffffff)&&(tagValue >= 0)&&(tagValue <= 0xffffffff)&&(!pairs[pk])) {
+						pairs[pk] = true;
+						ta.push([ tagId,tagValue ]);
+					}
+				}
+			}
+		}
+		ta.sort(function(a,b) {
+			return ((a[0] < b[0]) ? -1 : ((a[0] > b[0]) ? 1 : 0));
+		});
+		this._tags = ta;
+		return ta;
+	}
+
+	get creationTime() { return this.__creationTime; }
+	get lastAuthorizedTime() { return this.__lastAuthorizedTime; }
+	get lastAuthorizedCredentialType() { return this.__lastAuthorizedCredentialType; }
+	get lastAuthorizedCredential() { return this.__lastAuthorizedCredential; }
+	get lastDeauthorizedTime() { return this.__lastDeauthorizedTime; }
+	get physicalAddr() { return this.__physicalAddr; }
+	get revision() { return this.__revision; }
+	get vMajor() { return this.__vMajor; }
+	get vMinor() { return this.__vMinor; }
+	get vRev() { return this.__vRev; }
+	get vProto() { return this.__vProto; }
+
+	toJSONExcludeControllerGenerated()
+	{
+		return {
+			id: this.id,
+			nwid: this.nwid,
+			objtype: 'member',
+			address: this.id,
+			authorized: this.authorized,
+			activeBridge: this.activeBridge,
+			capabilities: this.capabilities,
+			identity: this.identity,
+			ipAssignments: this.ipAssignments,
+			noAutoAssignIps: this.noAutoAssignIps,
+			tags: this.tags
+		};
+	}
+
+	toJSON()
+	{
+		let j = this.toJSONExcludeControllerGenerated();
+		j.creationTime = this.creationTime;
+		j.lastAuthorizedTime = this.lastAuthorizedTime;
+		j.lastAuthorizedCredentialType = this.lastAuthorizedCredentialType;
+		j.lastAuthorizedCredential = this.lastAuthorizedCredential;
+		j.lastDeauthorizedTime = this.lastDeauthorizedTime;
+		j.physicalAddr = this.physicalAddr;
+		j.revision = this.revision;
+		j.vMajor = this.vMajor;
+		j.vMinor = this.vMinor;
+		j.vRev = this.vRev;
+		j.vProto = this.vProto;
+		return j;
 	}
 
 	clear()
@@ -542,5 +751,44 @@ class Member
 		this.__vRev = 0;
 		this.__vProto = 0;
 	}
+
+	patch(obj)
+	{
+		if (obj instanceof Member)
+			obj = obj.toJSON();
+		if ((obj)&&(typeof obj === 'object')&&(!Array.isArray(obj))) {
+			for(var k in obj) {
+				try {
+					switch(k) {
+						case 'id':
+						case 'nwid':
+						case 'authorized':
+						case 'activeBridge':
+						case 'capabilities':
+						case 'identity':
+						case 'ipAssignments':
+						case 'noAutoAssignIps':
+						case 'tags':
+							this[k] = obj[k];
+							break;
+
+						case 'creationTime':
+						case 'lastAuthorizedTime':
+						case 'lastAuthorizedCredentialType':
+						case 'lastAuthorizedCredential':
+						case 'lastDeauthorizedTime':
+						case 'physicalAddr':
+						case 'revision':
+						case 'vMajor':
+						case 'vMinor':
+						case 'vRev':
+						case 'vProto':
+							this['__'+k] = parseInt(obj[k])||0;
+							break;
+					}
+				} catch (e) {}
+			}
+		}
+	}
 };
 exports.Member = Member;