Subversion Repositories oidplus

Rev

Rev 751 | Go to most recent revision | Details | Last modification | View Log | RSS feed

Rev Author Line No. Line
750 daniel-mar 1
 
2
/**
3
 * WEID<=>OID Converter
4
 * (c) Webfan.de, ViaThinkSoft
5
 * Revision 2022-02-22
6
 **/
7
 
8
// What is a WEID?
9
//     A WEID (WEhowski IDentifier) is an alternative representation of an
10
//     OID (Object IDentifier) defined by Till Wehowski.
11
//     In OIDs, arcs are in decimal base 10. In WEIDs, the arcs are in base 36.
12
//     Also, each WEID has a check digit at the end (called WeLohn Check Digit).
13
//
14
// Changes in the December 2021 definition by Daniel Marschall:
15
//     - There are several classes of WEIDs which have different OID bases:
16
//           "Class C" WEID:  weid:EXAMPLE-3      (base .1.3.6.1.4.1.37553.8.)
17
//                            oid:1.3.6.1.4.1.37553.8.32488192274
18
//           "Class B" WEID:  weid:pen:SX0-7PR-6  (base .1.3.6.1.4.1.)
19
//                            oid:1.3.6.1.4.1.37476.9999
20
//           "Class A" WEID:  weid:root:2-RR-2    (base .)
21
//                            oid:2.999
22
//     - The namespace (weid:, weid:pen:, weid:root:) is now case insensitive.
23
//     - Padding with '0' characters is valid (e.g. weid:000EXAMPLE-3)
24
//       The paddings do not count into the WeLuhn check-digit.
25
 
26
// Requires "mikemcl/bignumber.js" library
27
 
28
var WeidOidConverter = {
29
 
30
        weLuhnCheckDigit: function(str) {
31
                // Padding zeros don't count to the check digit (December 2021)
32
                var ary = str.split('-');
33
                ary.forEach((o,i,a) => {
34
                        a[i] = a[i].replace(/^0+/, '');
35
                } );
36
                str = ary.join('-');
37
 
38
                // remove separators from the WEID string
39
                var wrkstr = str.replaceAll('-', '');
40
 
41
                // Replace 'a' with '10', 'b' with '1', etc.
42
                for (var i=0; i<26; i++) {
43
                        wrkstr = wrkstr.toLowerCase().replaceAll(String.fromCharCode('a'.charCodeAt(0)+i).toLowerCase(), (10+i));
44
                }
45
 
46
                // At the end, wrkstr should only contain digits! Verify it!
47
                if (!wrkstr.match(/^\d+$/)) return false;
48
 
49
                // Now do the standard Luhn algorithm
50
                var nbdigits = wrkstr.length;
51
                var parity = nbdigits & 1; // mod 2
52
                var sum = 0;
53
                for (var n=nbdigits-1; n>=0; n--) {
54
                        var digit = parseInt(wrkstr.substr(n,1));
55
                        if ((n & 1) != parity) digit *= 2;
56
                        if (digit > 9) digit -= 9;
57
                        sum += digit;
58
                }
59
                return (sum%10) == 0 ? 0 : 10-(sum%10);
60
        },
61
 
62
        // Translates a WEID to an OID
63
        // "weid:EXAMPLE-3" becomes "1.3.6.1.4.1.37553.8.32488192274"
64
        // If it failed (e.g. wrong namespace, wrong checksum, etc.) then false is returned.
65
        // If the weid ends with '?', the checksum will be added
66
        // Return value is an array with the elements "oid" and "weid".
67
        // Example:
68
        //     weid2oid("weid:EXAMPLE-?").weid == "weid:EXAMPLE-3"
69
        //     weid2oid("weid:EXAMPLE-?").oid  == "1.3.6.1.4.1.37553.8.32488192274"
70
        weid2oid: function(weid) {
71
                var p = weid.lastIndexOf(':');
72
                var namespace = weid.substr(0, p+1);
73
                var rest = weid.substr(p+1);
74
 
75
                namespace = namespace.toLowerCase(); // namespace is case insensitive
76
                if (namespace == 'weid:') {
77
                        // Class C
78
                        var base = '1-3-6-1-4-1-SZ5-8';
79
                } else if (namespace == 'weid:pen:') {
80
                        // Class B
81
                        var base = '1-3-6-1-4-1';
82
                } else if (namespace == 'weid:root:') {
83
                        // Class A
84
                        var base = '';
85
                } else {
86
                        // Wrong namespace
87
                        return false;
88
                }
89
 
90
                weid = rest;
91
 
92
                var elements = ((base != '') ? base.split('-') : []).concat(weid.split('-'));
93
                var actual_checksum = elements.pop();
94
                var expected_checksum = weLuhnCheckDigit(elements.join('-'));
95
                if (actual_checksum != '?') {
96
                        if (actual_checksum != expected_checksum) return false; // wrong checksum
97
                } else {
98
                        // If checksum is '?', it will be replaced by the actual checksum,
99
                        // e.g. weid:EXAMPLE-? becomes weid:EXAMPLE-3
100
                        weid = weid.replace('?', expected_checksum);
101
                }
102
                elements.forEach((o,i,a) => {
103
                        a[i] = BigNumber(a[i],36).toString(10).toUpperCase();
104
                });
105
                var oidstr = elements.join('.');
106
 
107
                weid = namespace.toLowerCase() + weid.toUpperCase(); // add namespace again
108
 
109
                return { "weid": weid, "oid" : oidstr };
110
        },
111
 
112
        // Converts an OID to WEID
113
        // "1.3.6.1.4.1.37553.8.32488192274" becomes "weid:EXAMPLE-3"
114
        oid2weid: function(oid) {
115
                if (oid.substr(0,1) == '.') oid = oid.substr(1); // remove leading dot
116
 
117
                if (oid != '') {
118
                        var elements = oid.split('.');
119
                        elements.forEach((o,i,a) => {
120
                                var x = BigNumber(a[i],10);
121
                                a[i] = x.toString(36).toUpperCase();
122
                        });
123
                        var weidstr = elements.join("-");
124
                } else {
125
                        var weidstr = '';
126
                }
127
 
128
                var is_class_c = (weidstr.startsWith('1-3-6-1-4-1-SZ5-8-') || (weidstr == '1-3-6-1-4-1-SZ5-8'));
129
                var is_class_b = (weidstr.startsWith('1-3-6-1-4-1-') || (weidstr == '1-3-6-1-4-1'));
130
                var is_class_a = !is_class_b && !is_class_c;
131
 
132
                var checksum = weLuhnCheckDigit(weidstr);
133
 
134
                if (is_class_c) {
135
                        weidstr = weidstr.substr('1-3-6-1-4-1-SZ5-8-'.length);
136
                        var namespace = 'weid:';
137
                } else if (is_class_b) {
138
                        weidstr = weidstr.substr('1-3-6-1-4-1-'.length);
139
                        var namespace = 'weid:pen:';
140
                } else if (is_class_a) {
141
                        // weidstr stays
142
                        var namespace = 'weid:root:';
143
                } else {
144
                        // should not happen
145
                        console.error("oid2weid: Cannot detect namespace");
146
                        return false;
147
                }
148
 
149
                return namespace + (weidstr == '' ? checksum : weidstr + '-' + checksum);
150
        }
151
 
152
}