line |
stmt |
bran |
cond |
sub |
pod |
time |
code |
1
|
|
|
|
|
|
|
## Domain Registry Interface, Mark & Signed Mark for EPP |
2
|
|
|
|
|
|
|
## |
3
|
|
|
|
|
|
|
## Copyright (c) 2013-2016 Patrick Mevzek . All rights reserved. |
4
|
|
|
|
|
|
|
## |
5
|
|
|
|
|
|
|
## This file is part of Net::DRI |
6
|
|
|
|
|
|
|
## |
7
|
|
|
|
|
|
|
## Net::DRI is free software; you can redistribute it and/or modify |
8
|
|
|
|
|
|
|
## it under the terms of the GNU General Public License as published by |
9
|
|
|
|
|
|
|
## the Free Software Foundation; either version 2 of the License, or |
10
|
|
|
|
|
|
|
## (at your option) any later version. |
11
|
|
|
|
|
|
|
## |
12
|
|
|
|
|
|
|
## See the LICENSE file that comes with this distribution for more details. |
13
|
|
|
|
|
|
|
#################################################################################################### |
14
|
|
|
|
|
|
|
|
15
|
|
|
|
|
|
|
package Net::DRI::Protocol::EPP::Extensions::ICANN::MarkSignedMark; |
16
|
|
|
|
|
|
|
|
17
|
1
|
|
|
1
|
|
960
|
use strict; |
|
1
|
|
|
|
|
1
|
|
|
1
|
|
|
|
|
23
|
|
18
|
1
|
|
|
1
|
|
2
|
use warnings; |
|
1
|
|
|
|
|
1
|
|
|
1
|
|
|
|
|
60
|
|
19
|
|
|
|
|
|
|
|
20
|
1
|
|
|
1
|
|
5
|
use Net::DRI::Util; |
|
1
|
|
|
|
|
1
|
|
|
1
|
|
|
|
|
47
|
|
21
|
1
|
|
|
1
|
|
4
|
use Net::DRI::Exception; |
|
1
|
|
|
|
|
1
|
|
|
1
|
|
|
|
|
18
|
|
22
|
1
|
|
|
1
|
|
3
|
use Net::DRI::Protocol::EPP::Util; |
|
1
|
|
|
|
|
1
|
|
|
1
|
|
|
|
|
16
|
|
23
|
|
|
|
|
|
|
|
24
|
1
|
|
|
1
|
|
180
|
use XML::LibXML (); |
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
25
|
|
|
|
|
|
|
use Encode; |
26
|
|
|
|
|
|
|
|
27
|
|
|
|
|
|
|
my $NS_XMLDSIG = 'http://www.w3.org/2000/09/xmldsig#'; |
28
|
|
|
|
|
|
|
|
29
|
|
|
|
|
|
|
#################################################################################################### |
30
|
|
|
|
|
|
|
|
31
|
|
|
|
|
|
|
sub setup |
32
|
|
|
|
|
|
|
{ |
33
|
|
|
|
|
|
|
my ($class,$po,$version)=@_; |
34
|
|
|
|
|
|
|
$po->ns({ 'mark' => [ 'urn:ietf:params:xml:ns:mark-1.0','mark-1.0.xsd' ], |
35
|
|
|
|
|
|
|
'signedMark' => [ 'urn:ietf:params:xml:ns:signedMark-1.0','signedMark-1.0'] }); |
36
|
|
|
|
|
|
|
return; |
37
|
|
|
|
|
|
|
} |
38
|
|
|
|
|
|
|
|
39
|
|
|
|
|
|
|
sub implements { return 'https://tools.ietf.org/html/draft-ietf-eppext-tmch-smd-06'; } |
40
|
|
|
|
|
|
|
|
41
|
|
|
|
|
|
|
my %xml2perl = ( trademark => 'trademark', |
42
|
|
|
|
|
|
|
treatyOrStatute => 'treaty_statute', |
43
|
|
|
|
|
|
|
court => 'court', |
44
|
|
|
|
|
|
|
markName => 'mark_name', |
45
|
|
|
|
|
|
|
goodsAndServices=> 'goods_services', |
46
|
|
|
|
|
|
|
apId => 'application_id', |
47
|
|
|
|
|
|
|
apDate => 'application_date', |
48
|
|
|
|
|
|
|
regNum => 'registration_number', |
49
|
|
|
|
|
|
|
regDate => 'registration_date', |
50
|
|
|
|
|
|
|
exDate => 'expiration_date', |
51
|
|
|
|
|
|
|
refNum => 'reference_number', |
52
|
|
|
|
|
|
|
proDate => 'protection_date', |
53
|
|
|
|
|
|
|
execDate => 'execution_date', |
54
|
|
|
|
|
|
|
courtName => 'court_name', |
55
|
|
|
|
|
|
|
); |
56
|
|
|
|
|
|
|
|
57
|
|
|
|
|
|
|
#################################################################################################### |
58
|
|
|
|
|
|
|
|
59
|
|
|
|
|
|
|
sub build_marks |
60
|
|
|
|
|
|
|
{ |
61
|
|
|
|
|
|
|
my ($po,$rd)=@_; |
62
|
|
|
|
|
|
|
Net::DRI::Exception::usererr_invalid_parameters('A ref array must be passed for marks, or a standalone ref hash for only one mark') unless defined $rd && (ref $rd eq 'ARRAY' || ref $rd eq 'HASH'); |
63
|
|
|
|
|
|
|
my @r; |
64
|
|
|
|
|
|
|
foreach my $m (ref $rd eq 'ARRAY' ? @$rd : $rd) |
65
|
|
|
|
|
|
|
{ |
66
|
|
|
|
|
|
|
push @r,['mark:mark',{ 'xmlns:mark' => $po->ns()->{'mark'}->[0]},build_mark($m)]; |
67
|
|
|
|
|
|
|
} |
68
|
|
|
|
|
|
|
return @r; |
69
|
|
|
|
|
|
|
} |
70
|
|
|
|
|
|
|
|
71
|
|
|
|
|
|
|
sub build_mark |
72
|
|
|
|
|
|
|
{ |
73
|
|
|
|
|
|
|
my ($rd)=@_; |
74
|
|
|
|
|
|
|
my @r; |
75
|
|
|
|
|
|
|
|
76
|
|
|
|
|
|
|
Net::DRI::Exception::usererr_invalid_parameters() unless defined $rd && ref $rd eq 'HASH'; |
77
|
|
|
|
|
|
|
my $type=$rd->{type}; |
78
|
|
|
|
|
|
|
$type='' unless defined $type; |
79
|
|
|
|
|
|
|
|
80
|
|
|
|
|
|
|
if ($type eq 'trademark' || exists $rd->{jurisdiction}) |
81
|
|
|
|
|
|
|
{ |
82
|
|
|
|
|
|
|
return _build_trademark($rd); |
83
|
|
|
|
|
|
|
} elsif ($type eq 'treaty_statute' || exists $rd->{protection}) |
84
|
|
|
|
|
|
|
{ |
85
|
|
|
|
|
|
|
return _build_treaty($rd); |
86
|
|
|
|
|
|
|
} elsif ($type eq 'court' || exists $rd->{court_name}) |
87
|
|
|
|
|
|
|
{ |
88
|
|
|
|
|
|
|
return _build_court($rd); |
89
|
|
|
|
|
|
|
} else |
90
|
|
|
|
|
|
|
{ |
91
|
|
|
|
|
|
|
Net::DRI::Exception::usererr_invalid_parameters(qq{Unrecognized type "$type" of mark, and no "jurisdiction", "protection" or "court_name" element}); |
92
|
|
|
|
|
|
|
} |
93
|
|
|
|
|
|
|
return; |
94
|
|
|
|
|
|
|
} |
95
|
|
|
|
|
|
|
|
96
|
|
|
|
|
|
|
sub _build_addr |
97
|
|
|
|
|
|
|
{ |
98
|
|
|
|
|
|
|
my ($contact)=@_; |
99
|
|
|
|
|
|
|
my (@r,$v); |
100
|
|
|
|
|
|
|
|
101
|
|
|
|
|
|
|
$v=scalar $contact->street(); |
102
|
|
|
|
|
|
|
Net::DRI::Exception::usererr_insufficient_parameters('Contact address must have from 1 to 3 street elements') unless defined $v && ref $v eq 'ARRAY' && @$v >=1 && @$v <= 3; |
103
|
|
|
|
|
|
|
push @r,map { ['mark:street',$_] } @$v; |
104
|
|
|
|
|
|
|
|
105
|
|
|
|
|
|
|
$v=scalar $contact->city(); |
106
|
|
|
|
|
|
|
Net::DRI::Exception::usererr_insufficient_parameters('Contact address must have a city') unless defined $v; |
107
|
|
|
|
|
|
|
Net::DRI::Exception::usererr_invalid_parameters('Contact address city must be an XML token string') unless Net::DRI::Util::xml_is_token($v); |
108
|
|
|
|
|
|
|
push @r,['mark:city',$v]; |
109
|
|
|
|
|
|
|
|
110
|
|
|
|
|
|
|
$v=scalar $contact->sp(); |
111
|
|
|
|
|
|
|
if (defined $v && length $v) |
112
|
|
|
|
|
|
|
{ |
113
|
|
|
|
|
|
|
Net::DRI::Exception::usererr_invalid_parameters('Contact address sp must be an XML token string') unless Net::DRI::Util::xml_is_token($v); |
114
|
|
|
|
|
|
|
push @r,['mark:sp',$v]; |
115
|
|
|
|
|
|
|
} |
116
|
|
|
|
|
|
|
|
117
|
|
|
|
|
|
|
$v=scalar $contact->pc(); |
118
|
|
|
|
|
|
|
if (defined $v && length $v) |
119
|
|
|
|
|
|
|
{ |
120
|
|
|
|
|
|
|
Net::DRI::Exception::usererr_invalid_parameters('Contact address pc must be an XML token string with 16 characters or less') unless Net::DRI::Util::xml_is_token($v,0,16); |
121
|
|
|
|
|
|
|
push @r,['mark:pc',$v]; |
122
|
|
|
|
|
|
|
} |
123
|
|
|
|
|
|
|
|
124
|
|
|
|
|
|
|
$v=scalar $contact->cc(); |
125
|
|
|
|
|
|
|
Net::DRI::Exception::usererr_insufficient_parameters('Contact address must have a cc') unless defined $v; |
126
|
|
|
|
|
|
|
Net::DRI::Exception::usererr_invalid_parameters('Contact address cc must be an XML token string of 2 characters') unless Net::DRI::Util::xml_is_token($v,2,2); |
127
|
|
|
|
|
|
|
push @r,['mark:cc',$v]; |
128
|
|
|
|
|
|
|
|
129
|
|
|
|
|
|
|
return @r; |
130
|
|
|
|
|
|
|
} |
131
|
|
|
|
|
|
|
|
132
|
|
|
|
|
|
|
sub _build_contact |
133
|
|
|
|
|
|
|
{ |
134
|
|
|
|
|
|
|
my ($type,$contact)=@_; |
135
|
|
|
|
|
|
|
|
136
|
|
|
|
|
|
|
Net::DRI::Exception::usererr_invalid_parameters('Element must be contact object, not: '.$contact) unless Net::DRI::Util::isa_contact($contact); |
137
|
|
|
|
|
|
|
|
138
|
|
|
|
|
|
|
my (@r,$v); |
139
|
|
|
|
|
|
|
|
140
|
|
|
|
|
|
|
$v=scalar $contact->name(); |
141
|
|
|
|
|
|
|
if (defined $v && length $v) |
142
|
|
|
|
|
|
|
{ |
143
|
|
|
|
|
|
|
Net::DRI::Exception::usererr_invalid_parameters('Name of contact must be an XML token string, not: '.$v) unless Net::DRI::Util::xml_is_token($v); |
144
|
|
|
|
|
|
|
push @r,['mark:name',$v]; |
145
|
|
|
|
|
|
|
} else |
146
|
|
|
|
|
|
|
{ |
147
|
|
|
|
|
|
|
Net::DRI::Exception::usererr_insufficient_parameters('Name is mandatory for a contact') if ($type eq 'contact'); |
148
|
|
|
|
|
|
|
} |
149
|
|
|
|
|
|
|
|
150
|
|
|
|
|
|
|
$v=scalar $contact->org(); |
151
|
|
|
|
|
|
|
if (defined $v && length $v) |
152
|
|
|
|
|
|
|
{ |
153
|
|
|
|
|
|
|
Net::DRI::Exception::usererr_invalid_parameters('Org of contact must be an XML token string, not: '.$v) unless Net::DRI::Util::xml_is_token($v); |
154
|
|
|
|
|
|
|
push @r,['mark:org',$v]; |
155
|
|
|
|
|
|
|
} |
156
|
|
|
|
|
|
|
|
157
|
|
|
|
|
|
|
Net::DRI::Exception::usererr_insufficient_parameters('holder must have a name or org') if $type eq 'holder' && ! @r; |
158
|
|
|
|
|
|
|
|
159
|
|
|
|
|
|
|
push @r,['mark:addr',_build_addr($contact)]; |
160
|
|
|
|
|
|
|
|
161
|
|
|
|
|
|
|
$v=$contact->voice(); |
162
|
|
|
|
|
|
|
if (defined $v && length $v) |
163
|
|
|
|
|
|
|
{ |
164
|
|
|
|
|
|
|
Net::DRI::Exception::usererr_invalid_parameters('Voice of contact must be an XML token string verifying pattern "(\+[0-9]{1,3}\.[0-9]{1,14})?"') unless Net::DRI::Util::xml_is_token($v,0,17) && $v=~m/^\+[0-9]{1,3}\.[0-9]{1,14}$/; |
165
|
|
|
|
|
|
|
push @r,Net::DRI::Protocol::EPP::Util::build_tel('mark:voice',$v); |
166
|
|
|
|
|
|
|
} else |
167
|
|
|
|
|
|
|
{ |
168
|
|
|
|
|
|
|
Net::DRI::Exception::usererr_insufficient_parameters('Voice is mandatory for a contact') if ($type eq 'contact'); |
169
|
|
|
|
|
|
|
} |
170
|
|
|
|
|
|
|
|
171
|
|
|
|
|
|
|
$v=$contact->fax(); |
172
|
|
|
|
|
|
|
if (defined $v && length $v) |
173
|
|
|
|
|
|
|
{ |
174
|
|
|
|
|
|
|
Net::DRI::Exception::usererr_invalid_parameters('Fax of contact must be an XML token string verifying pattern "(\+[0-9]{1,3}\.[0-9]{1,14})?"') unless Net::DRI::Util::xml_is_token($v,0,17) && $v=~m/^\+[0-9]{1,3}\.[0-9]{1,14}$/; |
175
|
|
|
|
|
|
|
push @r,Net::DRI::Protocol::EPP::Util::build_tel('mark:fax',$v); |
176
|
|
|
|
|
|
|
} |
177
|
|
|
|
|
|
|
|
178
|
|
|
|
|
|
|
$v=$contact->email(); |
179
|
|
|
|
|
|
|
if (defined $v && length $v) |
180
|
|
|
|
|
|
|
{ |
181
|
|
|
|
|
|
|
Net::DRI::Exception::usererr_invalid_parameters('Email of contact must be an XML token string with at least 1 character, not: '.$v) unless Net::DRI::Util::xml_is_token($v,1); |
182
|
|
|
|
|
|
|
push @r,['mark:email',$v]; |
183
|
|
|
|
|
|
|
} else |
184
|
|
|
|
|
|
|
{ |
185
|
|
|
|
|
|
|
Net::DRI::Exception::usererr_insufficient_parameters('Email is mandatory for a contact') if ($type eq 'contact'); |
186
|
|
|
|
|
|
|
} |
187
|
|
|
|
|
|
|
|
188
|
|
|
|
|
|
|
return @r; |
189
|
|
|
|
|
|
|
} |
190
|
|
|
|
|
|
|
|
191
|
|
|
|
|
|
|
sub _add_token |
192
|
|
|
|
|
|
|
{ |
193
|
|
|
|
|
|
|
my ($rd,$key,$optional)=@_; |
194
|
|
|
|
|
|
|
my $pkey=exists $xml2perl{$key} ? $xml2perl{$key} : $key; |
195
|
|
|
|
|
|
|
if (Net::DRI::Util::has_key($rd,$pkey)) |
196
|
|
|
|
|
|
|
{ |
197
|
|
|
|
|
|
|
Net::DRI::Exception::usererr_invalid_parameters(qq{Value for "$pkey" key must be an XML token string}) unless Net::DRI::Util::xml_is_token($rd->{$pkey}); |
198
|
|
|
|
|
|
|
return ['mark:'.$key,$rd->{$pkey}]; |
199
|
|
|
|
|
|
|
} else |
200
|
|
|
|
|
|
|
{ |
201
|
|
|
|
|
|
|
Net::DRI::Exception::usererr_insufficient_parameters(qq{"$pkey" key must exist}) unless (defined $optional && $optional); |
202
|
|
|
|
|
|
|
return; |
203
|
|
|
|
|
|
|
} |
204
|
|
|
|
|
|
|
} |
205
|
|
|
|
|
|
|
|
206
|
|
|
|
|
|
|
sub _add_datetime |
207
|
|
|
|
|
|
|
{ |
208
|
|
|
|
|
|
|
my ($rd,$key,$optional)=@_; |
209
|
|
|
|
|
|
|
my $pkey=exists $xml2perl{$key} ? $xml2perl{$key} : $key; |
210
|
|
|
|
|
|
|
if (Net::DRI::Util::has_key($rd,$pkey)) |
211
|
|
|
|
|
|
|
{ |
212
|
|
|
|
|
|
|
Net::DRI::Exception::usererr_invalid_parameters(qq{Value for "$pkey" key must be a DateTime object}) unless Net::DRI::Util::is_class($rd->{$pkey},'DateTime'); |
213
|
|
|
|
|
|
|
return ['mark:'.$key,Net::DRI::Util::dto2zstring($rd->{$pkey})]; |
214
|
|
|
|
|
|
|
} else |
215
|
|
|
|
|
|
|
{ |
216
|
|
|
|
|
|
|
Net::DRI::Exception::usererr_insufficient_parameters(qq{"$pkey" key must exist}) unless (defined $optional && $optional); |
217
|
|
|
|
|
|
|
return; |
218
|
|
|
|
|
|
|
} |
219
|
|
|
|
|
|
|
} |
220
|
|
|
|
|
|
|
|
221
|
|
|
|
|
|
|
sub _build_common1 |
222
|
|
|
|
|
|
|
{ |
223
|
|
|
|
|
|
|
my ($rd)=@_; |
224
|
|
|
|
|
|
|
my @r; |
225
|
|
|
|
|
|
|
|
226
|
|
|
|
|
|
|
push @r,_add_token($rd,'id'); |
227
|
|
|
|
|
|
|
Net::DRI::Exception::usererr_invalid_parameters('Value for "id" key must match pattern "\d+-\d+"') unless $rd->{id}=~m/^\d+-\d+$/; |
228
|
|
|
|
|
|
|
|
229
|
|
|
|
|
|
|
push @r,_add_token($rd,'markName'); |
230
|
|
|
|
|
|
|
|
231
|
|
|
|
|
|
|
Net::DRI::Exception::usererr_insufficient_parameters('"contact" key must exist') unless Net::DRI::Util::has_key($rd,'contact'); |
232
|
|
|
|
|
|
|
Net::DRI::Exception::usererr_invalid_parameters('Value for "contact" key must be a ContactSet object') unless Net::DRI::Util::isa_contactset($rd->{contact}); |
233
|
|
|
|
|
|
|
Net::DRI::Exception::usererr_insufficient_parameters('Value for "contact" key must have at least one contact of type holder_owner, holder_assignee or holder_licensee') unless grep { /^(?:holder_owner|holder_assignee|holder_licensee)$/ } $rd->{contact}->types(); |
234
|
|
|
|
|
|
|
foreach my $type (qw/owner assignee licensee/) |
235
|
|
|
|
|
|
|
{ |
236
|
|
|
|
|
|
|
my @o=$rd->{contact}->get('holder_'.$type); |
237
|
|
|
|
|
|
|
next unless @o; |
238
|
|
|
|
|
|
|
foreach my $c (@o) |
239
|
|
|
|
|
|
|
{ |
240
|
|
|
|
|
|
|
push @r,['mark:holder',{ entitlement => $type },_build_contact('holder',$c)]; |
241
|
|
|
|
|
|
|
} |
242
|
|
|
|
|
|
|
} |
243
|
|
|
|
|
|
|
foreach my $type (qw/owner agent thirdparty/) |
244
|
|
|
|
|
|
|
{ |
245
|
|
|
|
|
|
|
my @o=$rd->{contact}->get('contact_'.$type); |
246
|
|
|
|
|
|
|
next unless @o; |
247
|
|
|
|
|
|
|
foreach my $c (@o) |
248
|
|
|
|
|
|
|
{ |
249
|
|
|
|
|
|
|
push @r,['mark:contact',{ type => $type },_build_contact('contact',$c)]; |
250
|
|
|
|
|
|
|
} |
251
|
|
|
|
|
|
|
} |
252
|
|
|
|
|
|
|
|
253
|
|
|
|
|
|
|
return @r; |
254
|
|
|
|
|
|
|
} |
255
|
|
|
|
|
|
|
|
256
|
|
|
|
|
|
|
sub _build_common2 |
257
|
|
|
|
|
|
|
{ |
258
|
|
|
|
|
|
|
my ($rd)=@_; |
259
|
|
|
|
|
|
|
my @r; |
260
|
|
|
|
|
|
|
|
261
|
|
|
|
|
|
|
if (Net::DRI::Util::has_key($rd,'label')) |
262
|
|
|
|
|
|
|
{ |
263
|
|
|
|
|
|
|
foreach my $label (ref $rd->{label} eq 'ARRAY' ? @{$rd->{label}} : ($rd->{label})) |
264
|
|
|
|
|
|
|
{ |
265
|
|
|
|
|
|
|
Net::DRI::Exception::usererr_invalid_parameters(qq{Label "$label" must be an XML token string from 1 to 63 characters}) unless Net::DRI::Util::xml_is_token($label,1,63); |
266
|
|
|
|
|
|
|
Net::DRI::Exception::usererr_invalid_parameters(qq{Label "$label" must pass regex "[a-zA-Z0-9]([a-zA-Z0-9\-]*[a-zA-Z0-9])?"}) unless $label=~m/^[a-zA-Z0-9](?:[a-zA-Z0-9-]*[a-zA-Z0-9])?$/; |
267
|
|
|
|
|
|
|
push @r,['mark:label',$label]; |
268
|
|
|
|
|
|
|
} |
269
|
|
|
|
|
|
|
} |
270
|
|
|
|
|
|
|
|
271
|
|
|
|
|
|
|
push @r,_add_token($rd,'goodsAndServices'); |
272
|
|
|
|
|
|
|
|
273
|
|
|
|
|
|
|
return @r; |
274
|
|
|
|
|
|
|
} |
275
|
|
|
|
|
|
|
|
276
|
|
|
|
|
|
|
sub _build_common3 |
277
|
|
|
|
|
|
|
{ |
278
|
|
|
|
|
|
|
my ($rd)=@_; |
279
|
|
|
|
|
|
|
my @r; |
280
|
|
|
|
|
|
|
|
281
|
|
|
|
|
|
|
push @r,_add_token($rd,'refNum'); |
282
|
|
|
|
|
|
|
push @r,_add_datetime($rd,'proDate'); |
283
|
|
|
|
|
|
|
|
284
|
|
|
|
|
|
|
return @r; |
285
|
|
|
|
|
|
|
} |
286
|
|
|
|
|
|
|
|
287
|
|
|
|
|
|
|
sub _build_trademark |
288
|
|
|
|
|
|
|
{ |
289
|
|
|
|
|
|
|
my ($rd)=@_; |
290
|
|
|
|
|
|
|
my @r; |
291
|
|
|
|
|
|
|
|
292
|
|
|
|
|
|
|
push @r,_build_common1($rd); ## id/markName/holder/contact |
293
|
|
|
|
|
|
|
|
294
|
|
|
|
|
|
|
push @r,_add_token($rd,'jurisdiction'); |
295
|
|
|
|
|
|
|
Net::DRI::Exception::usererr_invalid_parameters(qq{Value for "jurisdiction" key must be an XML token string of 2 characters}) unless Net::DRI::Util::xml_is_token($rd->{jurisdiction},2,2); |
296
|
|
|
|
|
|
|
|
297
|
|
|
|
|
|
|
if (Net::DRI::Util::has_key($rd,'class')) |
298
|
|
|
|
|
|
|
{ |
299
|
|
|
|
|
|
|
foreach my $class (ref $rd->{class} eq 'ARRAY' ? @{$rd->{class}} : ($rd->{class})) |
300
|
|
|
|
|
|
|
{ |
301
|
|
|
|
|
|
|
Net::DRI::Exception::usererr_invalid_parameters('Class must be an integer, not: '.$class) unless $class=~m/^\d+$/; |
302
|
|
|
|
|
|
|
push @r,['mark:class',$class]; |
303
|
|
|
|
|
|
|
} |
304
|
|
|
|
|
|
|
} |
305
|
|
|
|
|
|
|
|
306
|
|
|
|
|
|
|
push @r,_build_common2($rd); ## label/goodsAndServices |
307
|
|
|
|
|
|
|
|
308
|
|
|
|
|
|
|
push @r,_add_token($rd,'apId',1); |
309
|
|
|
|
|
|
|
push @r,_add_datetime($rd,'apDate',1); |
310
|
|
|
|
|
|
|
push @r,_add_token($rd,'regNum'); |
311
|
|
|
|
|
|
|
push @r,_add_datetime($rd,'regDate'); |
312
|
|
|
|
|
|
|
push @r,_add_datetime($rd,'exDate',1); |
313
|
|
|
|
|
|
|
|
314
|
|
|
|
|
|
|
return ['mark:trademark',@r]; |
315
|
|
|
|
|
|
|
} |
316
|
|
|
|
|
|
|
|
317
|
|
|
|
|
|
|
sub _build_treaty |
318
|
|
|
|
|
|
|
{ |
319
|
|
|
|
|
|
|
my ($rd)=@_; |
320
|
|
|
|
|
|
|
my @r; |
321
|
|
|
|
|
|
|
|
322
|
|
|
|
|
|
|
push @r,_build_common1($rd); ## id/markName/holder/contact |
323
|
|
|
|
|
|
|
|
324
|
|
|
|
|
|
|
Net::DRI::Exception::usererr_insufficient_parameters('Key "protection" must exist') unless Net::DRI::Util::has_key($rd,'protection'); |
325
|
|
|
|
|
|
|
foreach my $rprot (ref $rd->{protection} eq 'ARRAY' ? @{$rd->{protection}} : ($rd->{protection})) |
326
|
|
|
|
|
|
|
{ |
327
|
|
|
|
|
|
|
my @pro; |
328
|
|
|
|
|
|
|
Net::DRI::Exception::usererr_invalid_parameters('Each protection item must be a ref hash, not: '.$rprot) unless ref $rprot eq 'HASH'; |
329
|
|
|
|
|
|
|
|
330
|
|
|
|
|
|
|
push @r,_add_token($rprot,'cc'); |
331
|
|
|
|
|
|
|
Net::DRI::Exception::usererr_invalid_parameters(qq{Value for "cc" key must be an XML token string of 2 characters}) unless Net::DRI::Util::xml_is_token($rprot->{cc},2,2); |
332
|
|
|
|
|
|
|
|
333
|
|
|
|
|
|
|
push @r,_add_token($rprot,'region',1); |
334
|
|
|
|
|
|
|
|
335
|
|
|
|
|
|
|
if (Net::DRI::Util::has_key($rprot,'ruling')) |
336
|
|
|
|
|
|
|
{ |
337
|
|
|
|
|
|
|
foreach my $ruling (ref $rprot->{ruling} eq 'ARRAY' ? @{$rprot->{ruling}} : ($rprot->{ruling})) |
338
|
|
|
|
|
|
|
{ |
339
|
|
|
|
|
|
|
push @r,_add_token({ ruling => $ruling },'ruling'); |
340
|
|
|
|
|
|
|
Net::DRI::Exception::usererr_invalid_parameters(qq{Each "ruling" item must be an XML token string of 2 characters}) unless Net::DRI::Util::xml_is_token($ruling,2,2); |
341
|
|
|
|
|
|
|
} |
342
|
|
|
|
|
|
|
} |
343
|
|
|
|
|
|
|
|
344
|
|
|
|
|
|
|
push @r,['mark:protection',@pro]; |
345
|
|
|
|
|
|
|
} |
346
|
|
|
|
|
|
|
|
347
|
|
|
|
|
|
|
push @r,_build_common2($rd); ## label/goodsAndServices |
348
|
|
|
|
|
|
|
push @r,_build_common3($rd); ## refNum/proDate |
349
|
|
|
|
|
|
|
|
350
|
|
|
|
|
|
|
push @r,_add_token($rd,'title'); |
351
|
|
|
|
|
|
|
push @r,_add_datetime($rd,'execDate'); |
352
|
|
|
|
|
|
|
|
353
|
|
|
|
|
|
|
return ['mark:treatyOrStatute',@r]; |
354
|
|
|
|
|
|
|
} |
355
|
|
|
|
|
|
|
|
356
|
|
|
|
|
|
|
sub _build_court |
357
|
|
|
|
|
|
|
{ |
358
|
|
|
|
|
|
|
my ($rd)=@_; |
359
|
|
|
|
|
|
|
my @r; |
360
|
|
|
|
|
|
|
|
361
|
|
|
|
|
|
|
push @r,_build_common1($rd); ## id/markName/holder/contact |
362
|
|
|
|
|
|
|
push @r,_build_common2($rd); ## label/goodsAndServices |
363
|
|
|
|
|
|
|
push @r,_build_common3($rd); ## refNum/proDate |
364
|
|
|
|
|
|
|
|
365
|
|
|
|
|
|
|
push @r,_add_token($rd,'cc'); |
366
|
|
|
|
|
|
|
Net::DRI::Exception::usererr_invalid_parameters(qq{Value for "cc" key must be an XML token string of 2 characters}) unless Net::DRI::Util::xml_is_token($rd->{cc},2,2); |
367
|
|
|
|
|
|
|
|
368
|
|
|
|
|
|
|
if (Net::DRI::Util::has_key($rd,'region')) |
369
|
|
|
|
|
|
|
{ |
370
|
|
|
|
|
|
|
foreach my $region (ref $rd->{region} eq 'ARRAY' ? @{$rd->{region}} : ($rd->{region})) |
371
|
|
|
|
|
|
|
{ |
372
|
|
|
|
|
|
|
push @r,_add_token({ region => $region },'region'); |
373
|
|
|
|
|
|
|
} |
374
|
|
|
|
|
|
|
} |
375
|
|
|
|
|
|
|
|
376
|
|
|
|
|
|
|
push @r,_add_token($rd,'courtName'); |
377
|
|
|
|
|
|
|
|
378
|
|
|
|
|
|
|
return ['mark:court',@r]; |
379
|
|
|
|
|
|
|
} |
380
|
|
|
|
|
|
|
|
381
|
|
|
|
|
|
|
#################################################################################################### |
382
|
|
|
|
|
|
|
|
383
|
|
|
|
|
|
|
sub parse_tel |
384
|
|
|
|
|
|
|
{ |
385
|
|
|
|
|
|
|
my ($node)=@_; |
386
|
|
|
|
|
|
|
my $r=$node->textContent(); |
387
|
|
|
|
|
|
|
$r.='x'.$node->getAttribute('x') if $node->hasAttribute('x'); |
388
|
|
|
|
|
|
|
return $r; |
389
|
|
|
|
|
|
|
} |
390
|
|
|
|
|
|
|
|
391
|
|
|
|
|
|
|
sub parse_contact |
392
|
|
|
|
|
|
|
{ |
393
|
|
|
|
|
|
|
my ($po,$start)=@_; |
394
|
|
|
|
|
|
|
my $contact=$po->create_local_object('contact'); |
395
|
|
|
|
|
|
|
|
396
|
|
|
|
|
|
|
foreach my $el (Net::DRI::Util::xml_list_children($start)) |
397
|
|
|
|
|
|
|
{ |
398
|
|
|
|
|
|
|
my ($name,$node)=@$el; |
399
|
|
|
|
|
|
|
if ($name=~m/^(?:name|org|email)$/) |
400
|
|
|
|
|
|
|
{ |
401
|
|
|
|
|
|
|
$contact->$name($node->textContent()); |
402
|
|
|
|
|
|
|
} elsif ($name=~m/^(?:voice|fax)$/) |
403
|
|
|
|
|
|
|
{ |
404
|
|
|
|
|
|
|
$contact->$name(parse_tel($node)); |
405
|
|
|
|
|
|
|
} elsif ($name eq 'addr') |
406
|
|
|
|
|
|
|
{ |
407
|
|
|
|
|
|
|
my @street; |
408
|
|
|
|
|
|
|
foreach my $subel (Net::DRI::Util::xml_list_children($node)) |
409
|
|
|
|
|
|
|
{ |
410
|
|
|
|
|
|
|
my ($addrname,$addrnode)=@$subel; |
411
|
|
|
|
|
|
|
if ($addrname eq 'street') |
412
|
|
|
|
|
|
|
{ |
413
|
|
|
|
|
|
|
push @street,$addrnode->textContent(); |
414
|
|
|
|
|
|
|
} elsif ($addrname=~m/^(?:city|sp|pc|cc)$/) |
415
|
|
|
|
|
|
|
{ |
416
|
|
|
|
|
|
|
$contact->$addrname($addrnode->textContent()); |
417
|
|
|
|
|
|
|
} |
418
|
|
|
|
|
|
|
} |
419
|
|
|
|
|
|
|
$contact->street(\@street); |
420
|
|
|
|
|
|
|
} elsif ($name=~m/^(?:voice|fax)$/) |
421
|
|
|
|
|
|
|
{ |
422
|
|
|
|
|
|
|
$contact->$name(Net::DRI::Protocol::EPP::Util::parse_tel($node)); |
423
|
|
|
|
|
|
|
} |
424
|
|
|
|
|
|
|
} |
425
|
|
|
|
|
|
|
|
426
|
|
|
|
|
|
|
return $contact; |
427
|
|
|
|
|
|
|
} |
428
|
|
|
|
|
|
|
|
429
|
|
|
|
|
|
|
sub parse_mark |
430
|
|
|
|
|
|
|
{ |
431
|
|
|
|
|
|
|
my ($po,$start)=@_; |
432
|
|
|
|
|
|
|
my @marks; |
433
|
|
|
|
|
|
|
|
434
|
|
|
|
|
|
|
foreach my $el (Net::DRI::Util::xml_list_children($start)) |
435
|
|
|
|
|
|
|
{ |
436
|
|
|
|
|
|
|
my ($name,$node)=@$el; |
437
|
|
|
|
|
|
|
if ($name=~m/^(?:trademark|treatyOrStatute|court)$/) |
438
|
|
|
|
|
|
|
{ |
439
|
|
|
|
|
|
|
my %m=(type => $xml2perl{$name}); |
440
|
|
|
|
|
|
|
my (@class,@label,@protection,@region); |
441
|
|
|
|
|
|
|
my $cs=$po->create_local_object('contactset'); |
442
|
|
|
|
|
|
|
foreach my $subel (Net::DRI::Util::xml_list_children($node)) |
443
|
|
|
|
|
|
|
{ |
444
|
|
|
|
|
|
|
my ($mname,$mnode)=@$subel; |
445
|
|
|
|
|
|
|
if ($mname=~m/^(id|markName|jurisdiction|goodsAndServices|apId|regNum|refNum|title|cc|courtName)$/) |
446
|
|
|
|
|
|
|
{ |
447
|
|
|
|
|
|
|
$m{exists $xml2perl{$mname} ? $xml2perl{$mname} : $mname}=$mnode->textContent(); |
448
|
|
|
|
|
|
|
} elsif ($mname eq 'holder') |
449
|
|
|
|
|
|
|
{ |
450
|
|
|
|
|
|
|
my $type='holder_'.$mnode->getAttribute('entitlement'); ## owner, assignee, licensee |
451
|
|
|
|
|
|
|
$cs->add(parse_contact($po,$mnode),$type); |
452
|
|
|
|
|
|
|
} elsif ($mname eq 'contact') |
453
|
|
|
|
|
|
|
{ |
454
|
|
|
|
|
|
|
my $type='contact_'.$mnode->getAttribute('type'); ## owner, agent, thirdparty |
455
|
|
|
|
|
|
|
$cs->add(parse_contact($po,$mnode),$type); |
456
|
|
|
|
|
|
|
} elsif ($mname eq 'class') |
457
|
|
|
|
|
|
|
{ |
458
|
|
|
|
|
|
|
push @class,$mnode->textContent(); |
459
|
|
|
|
|
|
|
} elsif ($mname eq 'label') |
460
|
|
|
|
|
|
|
{ |
461
|
|
|
|
|
|
|
push @label,$mnode->textContent(); |
462
|
|
|
|
|
|
|
} elsif ($mname=~m/^(?:apDate|regDate|exDate|proDate|execDate)$/) |
463
|
|
|
|
|
|
|
{ |
464
|
|
|
|
|
|
|
$m{$xml2perl{$mname}}=$po->parse_iso8601($mnode->textContent()); |
465
|
|
|
|
|
|
|
} elsif ($mname eq 'protection') |
466
|
|
|
|
|
|
|
{ |
467
|
|
|
|
|
|
|
my %p; |
468
|
|
|
|
|
|
|
foreach my $pel (Net::DRI::Util::xml_list_children($mnode)) |
469
|
|
|
|
|
|
|
{ |
470
|
|
|
|
|
|
|
my ($pname,$pnode)=@$pel; |
471
|
|
|
|
|
|
|
if ($pname=~m/^(cc|region)$/) |
472
|
|
|
|
|
|
|
{ |
473
|
|
|
|
|
|
|
$p{$pname}=$pnode->textContent(); |
474
|
|
|
|
|
|
|
} elsif ($pname eq 'ruling') |
475
|
|
|
|
|
|
|
{ |
476
|
|
|
|
|
|
|
push @{$p{ruling}},$pnode->textContent(); |
477
|
|
|
|
|
|
|
} |
478
|
|
|
|
|
|
|
} |
479
|
|
|
|
|
|
|
push @protection,\%p; |
480
|
|
|
|
|
|
|
} elsif ($mname eq 'region') |
481
|
|
|
|
|
|
|
{ |
482
|
|
|
|
|
|
|
push @region,$mnode->textContent(); |
483
|
|
|
|
|
|
|
} |
484
|
|
|
|
|
|
|
} |
485
|
|
|
|
|
|
|
$m{contact}=$cs; |
486
|
|
|
|
|
|
|
$m{class}=\@class if @class; |
487
|
|
|
|
|
|
|
$m{label}=\@label if @label; |
488
|
|
|
|
|
|
|
$m{protection}=\@protection if @protection; |
489
|
|
|
|
|
|
|
$m{region}=\@region if @region; |
490
|
|
|
|
|
|
|
if (exists $m{goods_services}) |
491
|
|
|
|
|
|
|
{ |
492
|
|
|
|
|
|
|
$m{goods_services}=~s/\n +/ /g; |
493
|
|
|
|
|
|
|
$m{goods_services}=~s/ +$//s; |
494
|
|
|
|
|
|
|
} |
495
|
|
|
|
|
|
|
push @marks,\%m; |
496
|
|
|
|
|
|
|
} |
497
|
|
|
|
|
|
|
} |
498
|
|
|
|
|
|
|
|
499
|
|
|
|
|
|
|
return \@marks; |
500
|
|
|
|
|
|
|
} |
501
|
|
|
|
|
|
|
|
502
|
|
|
|
|
|
|
sub lined_content |
503
|
|
|
|
|
|
|
{ |
504
|
|
|
|
|
|
|
my ($node,$signs,@keys)=@_; |
505
|
|
|
|
|
|
|
my $r=Net::DRI::Util::xml_traverse($node,$signs,@keys); |
506
|
|
|
|
|
|
|
return unless defined $r; |
507
|
|
|
|
|
|
|
$r=$r->textContent(); |
508
|
|
|
|
|
|
|
$r=~s/\s+//g; |
509
|
|
|
|
|
|
|
return $r; |
510
|
|
|
|
|
|
|
} |
511
|
|
|
|
|
|
|
|
512
|
|
|
|
|
|
|
sub parse_signed_mark |
513
|
|
|
|
|
|
|
{ |
514
|
|
|
|
|
|
|
my ($po,$start,$xmlsec)=@_; |
515
|
|
|
|
|
|
|
my %smark; |
516
|
|
|
|
|
|
|
|
517
|
|
|
|
|
|
|
foreach my $el (Net::DRI::Util::xml_list_children($start)) |
518
|
|
|
|
|
|
|
{ |
519
|
|
|
|
|
|
|
my ($name,$node)=@$el; |
520
|
|
|
|
|
|
|
if ($name eq 'id') |
521
|
|
|
|
|
|
|
{ |
522
|
|
|
|
|
|
|
$smark{id}=$node->textContent(); |
523
|
|
|
|
|
|
|
} elsif ($name eq 'issuerInfo') |
524
|
|
|
|
|
|
|
{ |
525
|
|
|
|
|
|
|
my %issuer=(id => $node->getAttribute('issuerID')); |
526
|
|
|
|
|
|
|
foreach my $iel (Net::DRI::Util::xml_list_children($node)) |
527
|
|
|
|
|
|
|
{ |
528
|
|
|
|
|
|
|
my ($iname,$inode)=@$iel; |
529
|
|
|
|
|
|
|
if ($iname=~m/^(?:org|email|url)$/) |
530
|
|
|
|
|
|
|
{ |
531
|
|
|
|
|
|
|
$issuer{$iname}=$inode->textContent(); |
532
|
|
|
|
|
|
|
} elsif ($iname eq 'voice') |
533
|
|
|
|
|
|
|
{ |
534
|
|
|
|
|
|
|
$issuer{$iname}=parse_tel($inode); |
535
|
|
|
|
|
|
|
} |
536
|
|
|
|
|
|
|
} |
537
|
|
|
|
|
|
|
$smark{issuer}=\%issuer; |
538
|
|
|
|
|
|
|
} elsif ($name eq 'notBefore') |
539
|
|
|
|
|
|
|
{ |
540
|
|
|
|
|
|
|
$smark{'creation_date'}=$po->parse_iso8601($node->textContent()); |
541
|
|
|
|
|
|
|
} elsif ($name eq 'notAfter') |
542
|
|
|
|
|
|
|
{ |
543
|
|
|
|
|
|
|
$smark{'expiration_date'}=$po->parse_iso8601($node->textContent()); |
544
|
|
|
|
|
|
|
} elsif ($name eq 'mark') |
545
|
|
|
|
|
|
|
{ |
546
|
|
|
|
|
|
|
$smark{mark}=parse_mark($po,$node); |
547
|
|
|
|
|
|
|
} elsif ($name eq 'Signature') |
548
|
|
|
|
|
|
|
{ |
549
|
|
|
|
|
|
|
my %s=(id => $start->getAttribute('id')); |
550
|
|
|
|
|
|
|
$s{'value'}=lined_content($node,$NS_XMLDSIG,qw/SignatureValue/); |
551
|
|
|
|
|
|
|
## TODO: handle other algorithms |
552
|
|
|
|
|
|
|
$s{'key'}={ algorithm => 'rsa', |
553
|
|
|
|
|
|
|
x509_certificate => lined_content($node,$NS_XMLDSIG,qw/KeyInfo X509Data X509Certificate/), |
554
|
|
|
|
|
|
|
}; |
555
|
|
|
|
|
|
|
$s{'validated'}=(defined $xmlsec && $xmlsec) ? _validate_xmldsig($start) : undef; |
556
|
|
|
|
|
|
|
$smark{'signature'}=\%s; |
557
|
|
|
|
|
|
|
} |
558
|
|
|
|
|
|
|
} |
559
|
|
|
|
|
|
|
return \%smark; |
560
|
|
|
|
|
|
|
} |
561
|
|
|
|
|
|
|
|
562
|
|
|
|
|
|
|
sub _validate_xmldsig |
563
|
|
|
|
|
|
|
{ |
564
|
|
|
|
|
|
|
my ($xml,$rs)=@_; |
565
|
|
|
|
|
|
|
|
566
|
|
|
|
|
|
|
require XML::LibXML::XPathContext; |
567
|
|
|
|
|
|
|
require Digest::SHA; |
568
|
|
|
|
|
|
|
require Crypt::OpenSSL::X509; |
569
|
|
|
|
|
|
|
require Crypt::OpenSSL::RSA; |
570
|
|
|
|
|
|
|
require MIME::Base64; |
571
|
|
|
|
|
|
|
|
572
|
|
|
|
|
|
|
my $xpc=XML::LibXML::XPathContext->new(); |
573
|
|
|
|
|
|
|
$xpc->registerNs('ds', $NS_XMLDSIG); |
574
|
|
|
|
|
|
|
|
575
|
|
|
|
|
|
|
foreach my $node ($xpc->findnodes('//ds:Reference',$xml)) |
576
|
|
|
|
|
|
|
{ |
577
|
|
|
|
|
|
|
my $for=$node->getAttribute('URI'); |
578
|
|
|
|
|
|
|
$for=~s/^#//; |
579
|
|
|
|
|
|
|
my $cnode=$xpc->findnodes("//*[\@id='${for}' or \@Id='${for}']",$xml); |
580
|
|
|
|
|
|
|
return 0 unless $cnode->size() == 1; |
581
|
|
|
|
|
|
|
|
582
|
|
|
|
|
|
|
$cnode=$cnode->get_node(1); ## node on which we perform the digest operation |
583
|
|
|
|
|
|
|
|
584
|
|
|
|
|
|
|
my %algos=map { $_->getAttribute('Algorithm') => 1 } $xpc->findnodes('ds:Transforms/ds:Transform',$node); |
585
|
|
|
|
|
|
|
return 0 unless exists $algos{'http://www.w3.org/2001/10/xml-exc-c14n#'}; |
586
|
|
|
|
|
|
|
|
587
|
|
|
|
|
|
|
my $xmlstring=$cnode->toStringEC14N(0,exists $algos{$NS_XMLDSIG.'enveloped-signature'} ? q{(. | .//node() | .//@* | .//namespace::*)[not(self::comment() or ancestor-or-self::ds:Signature)]} : undef,$xpc); |
588
|
|
|
|
|
|
|
|
589
|
|
|
|
|
|
|
return 0 unless defined $xmlstring && $xpc->findnodes('ds:DigestValue',$node)->get_node(1)->textContent() eq _sha256b64padded($xmlstring); |
590
|
|
|
|
|
|
|
} |
591
|
|
|
|
|
|
|
|
592
|
|
|
|
|
|
|
my $cert=$xpc->findnodes('//ds:X509Certificate',$xml)->get_node(1)->textContent(); |
593
|
|
|
|
|
|
|
$cert=~s/ /\n/g; |
594
|
|
|
|
|
|
|
my $certobj=Crypt::OpenSSL::X509->new_from_string("-----BEGIN CERTIFICATE-----\n".$cert."\n-----END CERTIFICATE-----", Crypt::OpenSSL::X509::FORMAT_PEM()); |
595
|
|
|
|
|
|
|
my $key=Crypt::OpenSSL::RSA->new_public_key($certobj->pubkey()); |
596
|
|
|
|
|
|
|
$key->use_sha256_hash(); |
597
|
|
|
|
|
|
|
|
598
|
|
|
|
|
|
|
my $xmlsi=$xpc->find('//ds:SignedInfo',$xml)->get_node(1); |
599
|
|
|
|
|
|
|
$xmlsi->setNamespace($NS_XMLDSIG,'ds',0); |
600
|
|
|
|
|
|
|
my $sigval=$xpc->findnodes('//ds:SignatureValue',$xmlsi)->get_node(1)->textContent(); |
601
|
|
|
|
|
|
|
$sigval=~s!\s+!!g; |
602
|
|
|
|
|
|
|
my $verify=$key->verify($xmlsi->toStringEC14N(0), MIME::Base64::decode_base64($sigval)); |
603
|
|
|
|
|
|
|
return (defined $verify && $verify) ? 1 : 0; |
604
|
|
|
|
|
|
|
} |
605
|
|
|
|
|
|
|
|
606
|
|
|
|
|
|
|
sub _sha256b64padded |
607
|
|
|
|
|
|
|
{ |
608
|
|
|
|
|
|
|
my ($in)=@_; |
609
|
|
|
|
|
|
|
my $out = Digest::SHA::sha256_base64($in); |
610
|
|
|
|
|
|
|
while (length($out) % 4) { $out .= '='; } |
611
|
|
|
|
|
|
|
return $out; |
612
|
|
|
|
|
|
|
} |
613
|
|
|
|
|
|
|
|
614
|
|
|
|
|
|
|
sub parse_encoded_signed_mark |
615
|
|
|
|
|
|
|
{ |
616
|
|
|
|
|
|
|
my ($po,$start,$xmlsec)=@_; |
617
|
|
|
|
|
|
|
my $content; |
618
|
|
|
|
|
|
|
|
619
|
|
|
|
|
|
|
if (ref $start) |
620
|
|
|
|
|
|
|
{ |
621
|
|
|
|
|
|
|
my $encoding=$start->hasAttribute('encoding') ? $start->getAttribute('encoding') : 'base64'; |
622
|
|
|
|
|
|
|
Net::DRI::Exception::err_invalid_parameter('For encoded signed mark, only base64 encoding is supported') unless $encoding eq 'base64'; |
623
|
|
|
|
|
|
|
$content=$start->textContent(); |
624
|
|
|
|
|
|
|
} else |
625
|
|
|
|
|
|
|
{ |
626
|
|
|
|
|
|
|
my @a=grep { /-----BEGIN ENCODED SMD-----/ .. /-----END ENCODED SMD-----/ } split(/\n/,$start); |
627
|
|
|
|
|
|
|
$content=join("\n",@a[1..($#a-1)]); |
628
|
|
|
|
|
|
|
} |
629
|
|
|
|
|
|
|
|
630
|
|
|
|
|
|
|
require MIME::Base64; |
631
|
|
|
|
|
|
|
my $xml=MIME::Base64::decode_base64($content); |
632
|
|
|
|
|
|
|
$xml=Encode::decode('UTF-8',$xml,Encode::FB_CROAK | Encode::LEAVE_SRC); |
633
|
|
|
|
|
|
|
my $root=XML::LibXML->load_xml(no_cdata => 1, no_blanks => 1, no_network => 1, string => $xml)->documentElement(); |
634
|
|
|
|
|
|
|
Net::DRI::Exception::err_invalid_parameter('Decoding should give a signedMark root element') unless $root->localname() eq 'signedMark'; |
635
|
|
|
|
|
|
|
|
636
|
|
|
|
|
|
|
return parse_signed_mark($po,$root,$xmlsec); |
637
|
|
|
|
|
|
|
} |
638
|
|
|
|
|
|
|
|
639
|
|
|
|
|
|
|
#################################################################################################### |
640
|
|
|
|
|
|
|
1; |
641
|
|
|
|
|
|
|
|
642
|
|
|
|
|
|
|
__END__ |