55package gleif
66
77import (
8- "context"
9- "encoding/json"
108 "errors"
11- "fmt"
12- "log/slog"
13- "strings"
14- "time"
159
16- "github.com/owasp-amass/amass/v4/engine/plugins/support"
1710 et "github.com/owasp-amass/amass/v4/engine/types"
18- "github.com/owasp-amass/amass/v4/utils/net/http"
1911 dbt "github.com/owasp-amass/asset-db/types"
2012 oam "github.com/owasp-amass/open-asset-model"
2113 "github.com/owasp-amass/open-asset-model/general"
22- "github.com/owasp-amass/open-asset-model/org"
2314 "go.uber.org/ratelimit"
2415)
2516
26- type gleif struct {
27- name string
28- log * slog.Logger
29- rlimit ratelimit.Limiter
30- fuzzy * fuzzyCompletions
31- related * relatedOrgs
32- source * et.Source
33- }
34-
3517func NewGLEIF () et.Plugin {
3618 return & gleif {
3719 name : "GLEIF" ,
@@ -92,253 +74,6 @@ func (g *gleif) Stop() {
9274 g .log .Info ("Plugin stopped" )
9375}
9476
95- type singleResponse struct {
96- Meta struct {
97- GoldenCopy struct {
98- PublishDate string `json:"publishDate"`
99- } `json:"goldenCopy"`
100- } `json:"meta"`
101- Data leiRecord `json:"data"`
102- }
103-
104- type multipleResponse struct {
105- Meta struct {
106- GoldenCopy struct {
107- PublishDate string `json:"publishDate"`
108- } `json:"goldenCopy"`
109- Pagination struct {
110- CurrentPage int `json:"currentPage"`
111- PerPage int `json:"perPage"`
112- From int `json:"from"`
113- To int `json:"to"`
114- Total int `json:"total"`
115- LastPage int `json:"lastPage"`
116- } `json:"pagination"`
117- } `json:"meta"`
118- Links struct {
119- First string `json:"first"`
120- Next string `json:"next"`
121- Last string `json:"last"`
122- } `json:"links"`
123- Data []leiRecord `json:"data"`
124- }
125-
126- type leiRecord struct {
127- Type string `json:"type"`
128- ID string `json:"id"`
129- Attributes struct {
130- LEI string `json:"lei"`
131- Entity struct {
132- LegalName struct {
133- Name string `json:"name"`
134- Lang string `json:"language"`
135- } `json:"legalName"`
136- OtherNames []string `json:"otherNames"`
137- TransliteratedOtherNames []string `json:"transliteratedOtherNames"`
138- LegalAddress leiAddress `json:"legalAddress"`
139- HeadquartersAddress leiAddress `json:"headquartersAddress"`
140- RegisteredAt struct {
141- ID string `json:"id"`
142- Other string `json:"other"`
143- } `json:"registeredAt"`
144- RegisteredAs string `json:"registeredAs"`
145- Jurisdiction string `json:"jurisdiction"`
146- Category string `json:"category"`
147- LegalForm struct {
148- ID string `json:"id"`
149- Other string `json:"other"`
150- } `json:"legalForm"`
151- AssociatedEntity leiEntity `json:"associatedEntity"`
152- Status string `json:"status"`
153- Expiration struct {
154- Date string `json:"date"`
155- Reason string `json:"reason"`
156- } `json:"expiration"`
157- SuccessorEntity leiEntity `json:"successorEntity"`
158- SuccessorEntities []leiEntity `json:"successorEntities"`
159- CreationDate string `json:"creationDate"`
160- SubCategory string `json:"subCategory"`
161- OtherAddresses []leiAddress `json:"otherAddresses"`
162- EventGroups []string `json:"eventGroups"`
163- } `json:"entity"`
164- Registration struct {
165- InitialRegistrationDate string `json:"initialRegistrationDate"`
166- LastUpdateDate string `json:"lastUpdateDate"`
167- Status string `json:"status"`
168- NextRenewalDate string `json:"nextRenewalDate"`
169- ManagingLOU string `json:"managingLou"`
170- CorroborationLevel string `json:"corroborationLevel"`
171- ValidatedAt struct {
172- ID string `json:"id"`
173- Other string `json:"other"`
174- } `json:"validatedAt"`
175- ValidatedAs string `json:"validatedAs"`
176- OtherValidationAuthorities []string `json:"otherValidationAuthorities"`
177- } `json:"registration"`
178- BIC string `json:"bic"`
179- MIC string `json:"mic"`
180- OCID string `json:"ocid"`
181- SPGlobal []string `json:"spglobal"`
182- ConformityFlag string `json:"conformityFlag"`
183- } `json:"attributes"`
184- Relationships struct {
185- ManagingLOU struct {
186- Links leiRelationshipLinks `json:"links"`
187- } `json:"managing-lou"`
188- LEIIssuer struct {
189- Links leiRelationshipLinks `json:"links"`
190- } `json:"lei-issuer"`
191- FieldModifications struct {
192- Links leiRelationshipLinks `json:"links"`
193- } `json:"field-modifications"`
194- DirectParent struct {
195- Links leiRelationshipLinks `json:"links"`
196- } `json:"direct-parent"`
197- UltimateParent struct {
198- Links leiRelationshipLinks `json:"links"`
199- } `json:"ultimate-parent"`
200- DirectChildren struct {
201- Links leiRelationshipLinks `json:"links"`
202- } `json:"direct-children"`
203- UltimateChildren struct {
204- Links leiRelationshipLinks `json:"links"`
205- } `json:"ultimate-children"`
206- ISINs struct {
207- Links leiRelationshipLinks `json:"links"`
208- } `json:"isins"`
209- } `json:"relationships"`
210- Links struct {
211- Self string `json:"self"`
212- } `json:"links"`
213- }
214-
215- type leiEntity struct {
216- LEI string `json:"lei"`
217- Name string `json:"name"`
218- }
219-
220- type leiAddress struct {
221- Lang string `json:"language"`
222- AddressLines []string `json:"addressLines"`
223- AddressNumber string `json:"addressNumber"`
224- AddressNumberWithinBuilding string `json:"addressNumberWithinBuilding"`
225- MailRouting string `json:"mailRouting"`
226- City string `json:"city"`
227- Region string `json:"region"`
228- Country string `json:"country"`
229- PostalCode string `json:"postalCode"`
230- }
231-
232- type leiRelationshipLinks struct {
233- Related string `json:"related"`
234- LEIRecord string `json:"lei-record"`
235- RelationshipRecord string `json:"relationship-record"`
236- RelationshipRecords string `json:"relationship-records"`
237- ReportingException string `json:"reporting-exception"`
238- }
239-
240- func (g * gleif ) getLEIRecord (ident * general.Identifier ) (* leiRecord , error ) {
241- g .rlimit .Take ()
242-
243- u := "https://api.gleif.org/api/v1/lei-records/" + ident .EntityID
244- resp , err := http .RequestWebPage (context .TODO (), & http.Request {URL : u })
245- if err != nil || resp .Body == "" {
246- return nil , err
247- }
248-
249- var result singleResponse
250- if err := json .Unmarshal ([]byte (resp .Body ), & result ); err != nil {
251- return nil , err
252- } else if len (result .Data .ID ) == 0 || result .Data .Type != "lei-records" {
253- return nil , errors .New ("failed to find the LEI record" )
254- }
255- return & result .Data , nil
256- }
257-
258- func (g * gleif ) orgEntityToLEI (e * et.Event , orgent * dbt.Entity ) * dbt.Entity {
259- if edges , err := e .Session .Cache ().OutgoingEdges (orgent , time.Time {}, "id" ); err == nil {
260- for _ , edge := range edges {
261- if a , err := e .Session .Cache ().FindEntityById (edge .ToEntity .ID ); err == nil && a != nil {
262- if id , ok := a .Asset .(* general.Identifier ); ok && id .Type == general .LEICode {
263- return a
264- }
265- }
266- }
267- }
268- return nil
269- }
270-
271- func (g * gleif ) leiToOrgEntity (e * et.Event , ident * dbt.Entity ) * dbt.Entity {
272- if edges , err := e .Session .Cache ().IncomingEdges (ident , time.Time {}, "id" ); err == nil {
273- for _ , edge := range edges {
274- if a , err := e .Session .Cache ().FindEntityById (edge .FromEntity .ID ); err == nil && a != nil {
275- if _ , ok := a .Asset .(* org.Organization ); ok {
276- return a
277- }
278- }
279- }
280- }
281- return nil
282- }
283-
284- func (g * gleif ) updateOrgFromLEIRecord (e * et.Event , orgent * dbt.Entity , lei * leiRecord ) {
285- o := orgent .Asset .(* org.Organization )
286-
287- o .LegalName = lei .Attributes .Entity .LegalName .Name
288- o .FoundingDate = lei .Attributes .Entity .CreationDate
289- if lei .Attributes .Entity .Status == "ACTIVE" {
290- o .Active = true
291- } else {
292- o .Active = false
293- }
294-
295- street := strings .Join (lei .Attributes .Entity .HeadquartersAddress .AddressLines , " " )
296- city := lei .Attributes .Entity .HeadquartersAddress .City
297- province := lei .Attributes .Entity .HeadquartersAddress .Region
298- postalCode := lei .Attributes .Entity .HeadquartersAddress .PostalCode
299- country := lei .Attributes .Entity .HeadquartersAddress .Country
300-
301- addr := fmt .Sprintf ("%s %s %s %s %s" , street , city , province , postalCode , country )
302- _ = g .addAddress (e , orgent , general.SimpleRelation {Name : "location" }, addr )
303-
304- _ , _ = e .Session .Cache ().CreateEntity (orgent )
305- }
306-
307- func (g * gleif ) addAddress (e * et.Event , orgent * dbt.Entity , rel oam.Relation , addr string ) error {
308- loc := support .StreetAddressToLocation (addr )
309- if loc == nil {
310- return errors .New ("failed to create location" )
311- }
312-
313- a , err := e .Session .Cache ().CreateAsset (loc )
314- if err != nil || a == nil {
315- e .Session .Log ().Error (err .Error (), slog .Group ("plugin" , "name" , g .name , "handler" , g .name ))
316- return err
317- }
318-
319- _ , _ = e .Session .Cache ().CreateEntityProperty (a , & general.SourceProperty {
320- Source : g .source .Name ,
321- Confidence : g .source .Confidence ,
322- })
323-
324- edge , err := e .Session .Cache ().CreateEdge (& dbt.Edge {
325- Relation : rel ,
326- FromEntity : orgent ,
327- ToEntity : a ,
328- })
329- if err != nil && edge == nil {
330- e .Session .Log ().Error (err .Error (), slog .Group ("plugin" , "name" , g .name , "handler" , g .name ))
331- return err
332- }
333-
334- _ , _ = e .Session .Cache ().CreateEdgeProperty (edge , & general.SourceProperty {
335- Source : g .source .Name ,
336- Confidence : g .source .Confidence ,
337- })
338-
339- return nil
340- }
341-
34277func (g * gleif ) createRelation (session et.Session , obj * dbt.Entity , rel oam.Relation , subject * dbt.Entity ) error {
34378 edge , err := session .Cache ().CreateEdge (& dbt.Edge {
34479 Relation : rel ,
@@ -357,31 +92,3 @@ func (g *gleif) createRelation(session et.Session, obj *dbt.Entity, rel oam.Rela
35792 })
35893 return err
35994}
360-
361- func (g * gleif ) createLEIIdentifier (session et.Session , orgent * dbt.Entity , lei * general.Identifier ) (* dbt.Entity , error ) {
362- id , err := session .Cache ().CreateAsset (lei )
363- if err != nil {
364- return nil , err
365- } else if id == nil {
366- return nil , errors .New ("failed to create the Identifier asset" )
367- }
368-
369- if orgent != nil {
370- if err := g .createRelation (session , orgent , general.SimpleRelation {Name : "id" }, id ); err != nil {
371- return nil , err
372- }
373- }
374- return id , nil
375- }
376-
377- func (g * gleif ) createLEIFromRecord (e * et.Event , orgent * dbt.Entity , lei * leiRecord ) (* dbt.Entity , error ) {
378- return g .createLEIIdentifier (e .Session , orgent , & general.Identifier {
379- UniqueID : fmt .Sprintf ("%s:%s" , general .LEICode , lei .ID ),
380- EntityID : lei .ID ,
381- Type : general .LEICode ,
382- Status : lei .Attributes .Registration .Status ,
383- CreationDate : lei .Attributes .Registration .InitialRegistrationDate ,
384- UpdatedDate : lei .Attributes .Registration .LastUpdateDate ,
385- ExpirationDate : lei .Attributes .Registration .NextRenewalDate ,
386- })
387- }
0 commit comments