1 |
|
2 |
|
3 | var assert = require('assert');
|
4 |
|
5 | var asn1 = require('asn1');
|
6 |
|
7 | var Protocol = require('./protocol');
|
8 |
|
9 |
|
10 |
|
11 |
|
12 | function Attribute(options) {
|
13 | if (options) {
|
14 | if (typeof (options) !== 'object')
|
15 | throw new TypeError('options must be an object');
|
16 | if (options.type && typeof (options.type) !== 'string')
|
17 | throw new TypeError('options.type must be a string');
|
18 | } else {
|
19 | options = {};
|
20 | }
|
21 |
|
22 | this.type = options.type || '';
|
23 | this._vals = [];
|
24 |
|
25 | if (options.vals !== undefined && options.vals !== null)
|
26 | this.vals = options.vals;
|
27 | }
|
28 |
|
29 | module.exports = Attribute;
|
30 |
|
31 | Object.defineProperties(Attribute.prototype, {
|
32 | buffers: {
|
33 | get: function getBuffers() {
|
34 | return this._vals;
|
35 | },
|
36 | configurable: false
|
37 | },
|
38 | json: {
|
39 | get: function getJson() {
|
40 | return {
|
41 | type: this.type,
|
42 | vals: this.vals
|
43 | };
|
44 | },
|
45 | configurable: false
|
46 | },
|
47 | vals: {
|
48 | get: function getVals() {
|
49 | var eType = _bufferEncoding(this.type);
|
50 | return this._vals.map(function (v) {
|
51 | return v.toString(eType);
|
52 | });
|
53 | },
|
54 | set: function setVals(vals) {
|
55 | var self = this;
|
56 | this._vals = [];
|
57 | if (Array.isArray(vals)) {
|
58 | vals.forEach(function (v) {
|
59 | self.addValue(v);
|
60 | });
|
61 | } else {
|
62 | self.addValue(vals);
|
63 | }
|
64 | },
|
65 | configurable: false
|
66 | }
|
67 | });
|
68 |
|
69 |
|
70 | Attribute.prototype.addValue = function addValue(val) {
|
71 | if (Buffer.isBuffer(val)) {
|
72 | this._vals.push(val);
|
73 | } else {
|
74 | this._vals.push(new Buffer(val + '', _bufferEncoding(this.type)));
|
75 | }
|
76 | };
|
77 |
|
78 |
|
79 |
|
80 | Attribute.compare = function compare(a, b) {
|
81 | if (!(Attribute.isAttribute(a)) || !(Attribute.isAttribute(b))) {
|
82 | throw new TypeError('can only compare Attributes');
|
83 | }
|
84 |
|
85 | if (a.type < b.type) return -1;
|
86 | if (a.type > b.type) return 1;
|
87 | if (a.vals.length < b.vals.length) return -1;
|
88 | if (a.vals.length > b.vals.length) return 1;
|
89 |
|
90 | for (var i = 0; i < a.vals.length; i++) {
|
91 | if (a.vals[i] < b.vals[i]) return -1;
|
92 | if (a.vals[i] > b.vals[i]) return 1;
|
93 | }
|
94 |
|
95 | return 0;
|
96 | };
|
97 |
|
98 |
|
99 |
|
100 | Attribute.prototype.parse = function parse(ber) {
|
101 | assert.ok(ber);
|
102 |
|
103 | ber.readSequence();
|
104 | this.type = ber.readString();
|
105 |
|
106 | if (ber.peek() === Protocol.LBER_SET) {
|
107 | if (ber.readSequence(Protocol.LBER_SET)) {
|
108 | var end = ber.offset + ber.length;
|
109 | while (ber.offset < end)
|
110 | this._vals.push(ber.readString(asn1.Ber.OctetString, true));
|
111 | }
|
112 | }
|
113 |
|
114 | return true;
|
115 | };
|
116 |
|
117 |
|
118 | Attribute.prototype.toBer = function toBer(ber) {
|
119 | assert.ok(ber);
|
120 |
|
121 | ber.startSequence();
|
122 | ber.writeString(this.type);
|
123 | ber.startSequence(Protocol.LBER_SET);
|
124 | if (this._vals.length) {
|
125 | this._vals.forEach(function (b) {
|
126 | ber.writeByte(asn1.Ber.OctetString);
|
127 | ber.writeLength(b.length);
|
128 | for (var i = 0; i < b.length; i++)
|
129 | ber.writeByte(b[i]);
|
130 | });
|
131 | } else {
|
132 | ber.writeStringArray([]);
|
133 | }
|
134 | ber.endSequence();
|
135 | ber.endSequence();
|
136 |
|
137 | return ber;
|
138 | };
|
139 |
|
140 |
|
141 | Attribute.prototype.toString = function () {
|
142 | return JSON.stringify(this.json);
|
143 | };
|
144 |
|
145 |
|
146 | Attribute.toBer = function (attr, ber) {
|
147 | return Attribute.prototype.toBer.call(attr, ber);
|
148 | };
|
149 |
|
150 |
|
151 | Attribute.isAttribute = function isAttribute(attr) {
|
152 | if (!attr || typeof (attr) !== 'object') {
|
153 | return false;
|
154 | }
|
155 | if (attr instanceof Attribute) {
|
156 | return true;
|
157 | }
|
158 | if ((typeof (attr.toBer) === 'function') &&
|
159 | (typeof (attr.type) === 'string') &&
|
160 | (Array.isArray(attr.vals)) &&
|
161 | (attr.vals.filter(function (item) {
|
162 | return (typeof (item) === 'string' ||
|
163 | Buffer.isBuffer(item));
|
164 | }).length === attr.vals.length)) {
|
165 | return true;
|
166 | }
|
167 | return false;
|
168 | };
|
169 |
|
170 |
|
171 | function _bufferEncoding(type) {
|
172 |
|
173 | return /;binary$/.test(type) ? 'base64' : 'utf8';
|
174 | }
|