• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

knowledgepixels / nanodash / 17614299597

10 Sep 2025 12:50PM UTC coverage: 13.827% (+0.004%) from 13.823%
17614299597

push

github

ashleycaselli
fix(UserData): add check on ApiResponseEntry to handle empty value for keyLocation

432 of 3946 branches covered (10.95%)

Branch coverage included in aggregate %.

1106 of 7177 relevant lines covered (15.41%)

0.69 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

31.42
src/main/java/com/knowledgepixels/nanodash/UserData.java
1
package com.knowledgepixels.nanodash;
2

3
import org.eclipse.rdf4j.common.exception.RDF4JException;
4
import org.eclipse.rdf4j.model.IRI;
5
import org.eclipse.rdf4j.model.ValueFactory;
6
import org.eclipse.rdf4j.model.impl.SimpleValueFactory;
7
import org.nanopub.MalformedNanopubException;
8
import org.nanopub.Nanopub;
9
import org.nanopub.SimpleTimestampPattern;
10
import org.nanopub.extra.security.MalformedCryptoElementException;
11
import org.nanopub.extra.security.NanopubSignatureElement;
12
import org.nanopub.extra.security.SignatureUtils;
13
import org.nanopub.extra.server.GetNanopub;
14
import org.nanopub.extra.services.ApiResponseEntry;
15
import org.nanopub.extra.setting.IntroNanopub;
16
import org.nanopub.extra.setting.NanopubSetting;
17
import org.nanopub.vocabulary.NPX;
18
import org.slf4j.Logger;
19
import org.slf4j.LoggerFactory;
20

21
import java.io.IOException;
22
import java.io.Serializable;
23
import java.util.*;
24

25
/**
26
 * UserData class manages user-related data.
27
 */
28
public class UserData implements Serializable {
29

30
    private static final long serialVersionUID = 1L;
31

32
    private static ValueFactory vf = SimpleValueFactory.getInstance();
2✔
33
    private static final Logger logger = LoggerFactory.getLogger(UserData.class);
4✔
34

35
    private HashMap<IRI, Set<String>> approvedIdPubkeyhashMap = new HashMap<>();
5✔
36
    private HashMap<String, Set<IRI>> approvedPubkeyhashIdMap = new HashMap<>();
5✔
37
    private HashMap<String, Set<IRI>> approvedPubkeyhashLocationMap = new HashMap<>();
5✔
38
    private HashMap<IRI, Set<String>> unapprovedIdPubkeyhashMap = new HashMap<>();
5✔
39
    private HashMap<String, Set<IRI>> unapprovedPubkeyhashIdMap = new HashMap<>();
5✔
40
    private HashMap<String, Set<IRI>> unapprovedPubkeyhashLocationMap = new HashMap<>();
5✔
41
    private HashMap<String, Set<IRI>> pubkeyhashIntroMap = new HashMap<>();
5✔
42
    private HashMap<IRI, IntroNanopub> introMap = new HashMap<>();
5✔
43
    private Set<IRI> approvedIntros = new HashSet<>();
5✔
44
    private HashMap<IRI, String> idNameMap = new HashMap<>();
5✔
45
    private HashMap<IRI, List<IntroNanopub>> introNanopubLists = new HashMap<>();
5✔
46

47
    /**
48
     * Default constructor for UserData.
49
     * Initializes the user data by fetching nanopublications settings.
50
     */
51
    UserData() {
2✔
52
        final NanodashPreferences pref = NanodashPreferences.get();
2✔
53

54
        // TODO Make nanopublication setting configurable:
55
        NanopubSetting setting;
56
        if (pref.getSettingUri() != null) {
3!
57
            setting = new NanopubSetting(GetNanopub.get(pref.getSettingUri()));
×
58
        } else {
59
            try {
60
                setting = NanopubSetting.getLocalSetting();
2✔
61
            } catch (RDF4JException | MalformedNanopubException | IOException ex) {
×
62
                throw new RuntimeException(ex);
×
63
            }
1✔
64
        }
65
        String settingId = setting.getNanopub().getUri().stringValue();
5✔
66
        if (setting.getUpdateStrategy().equals(NPX.UPDATES_BY_CREATOR)) {
5!
67
            settingId = QueryApiAccess.getLatestVersionId(settingId);
3✔
68
            setting = new NanopubSetting(GetNanopub.get(settingId));
6✔
69
        }
70
        logger.info("Using nanopublication setting: {}", settingId);
4✔
71

72
//                // Get users that are listed directly in the authority index, and consider them approved:
73
//                ByteArrayOutputStream out = new ByteArrayOutputStream(); // TODO use piped out-in stream here
74
//                new FetchIndex(setting.getAgentIntroCollection().stringValue(), out, RDFFormat.TRIG, false, true, null).run();
75
//                InputStream in = new ByteArrayInputStream(out.toByteArray());
76
//                try {
77
//                        MultiNanopubRdfHandler.process(RDFFormat.TRIG, in, new MultiNanopubRdfHandler.NanopubHandler() {
78
//                                @Override
79
//                                public void handleNanopub(Nanopub np) {
80
//                                        // TODO: Check that latest version talks about same user
81
//                                        register(QueryApiAccess.getLatestVersionId(np.getUri().stringValue()), true);
82
//                                }
83
//                        });
84
//                } catch (RDFParseException | RDFHandlerException | IOException | MalformedNanopubException ex) {
85
//                        logger.error();
86
//                }
87
///
88
//                if (setting.getTrustRangeAlgorithm().equals(NPX.TRANSITIVE_TRUST)) {
89
//                        ApiResponse resp = QueryApiAccess.forcedGet("get-approved-nanopubs");
90
//                        List<ApiResponseEntry> results = new ArrayList<>(resp.getData());
91
//                        while (true) {
92
//                                boolean keepLooping = false;
93
//                                for (ApiResponseEntry entry : new ArrayList<>(results)) {
94
//                                        if (hasValue(approvedPubkeyIdMap, entry.get("pubkey"), Utils.vf.createIRI(entry.get("approver")))) {
95
//                                                register(entry.get("approved_np"), true);
96
//                                                results.remove(entry);
97
//                                                keepLooping = true;
98
//                                        }
99
//                                }
100
//                                if (!keepLooping) break;
101
//                        }
102
//                }
103

104
        logger.info("Loading approved users...");
3✔
105
        try {
106
            for (RegistryAccountInfo rai : RegistryAccountInfo.fromUrl(Utils.getMainRegistryUrl() + "list.json")) {
12✔
107
                registerApproved(rai);
3✔
108
            }
1✔
109
        } catch (Exception ex) {
×
110
            throw new RuntimeException(ex);
×
111
        }
1✔
112

113
        logger.info("Loading user details...");
3✔
114
        // Get latest introductions for all users, including unapproved ones:
115
        for (ApiResponseEntry entry : QueryApiAccess.forcedGet("get-all-user-intros").getData()) {
12✔
116
            register(entry);
3✔
117
        }
1✔
118
    }
1✔
119

120
    private IntroNanopub toIntroNanopub(IRI iri) {
121
        if (iri == null) return null;
×
122
        if (introMap.containsKey(iri)) return introMap.get(iri);
×
123
        Nanopub np = Utils.getNanopub(iri.stringValue());
×
124
        if (np == null) return null;
×
125
        IntroNanopub introNp = new IntroNanopub(np);
×
126
        introMap.put(np.getUri(), introNp);
×
127
        return introNp;
×
128
    }
129

130
    private void registerApproved(RegistryAccountInfo rai) {
131
        if (rai.getAgent().equals("$")) return;
6✔
132
        addValue(approvedIdPubkeyhashMap, rai.getAgentIri(), rai.getPubkey());
8✔
133
        addValue(approvedPubkeyhashIdMap, rai.getPubkey(), rai.getAgentIri());
8✔
134
    }
1✔
135

136
    private void register(ApiResponseEntry entry) {
137
        IRI userIri;
138
        try {
139
            userIri = vf.createIRI(entry.get("user"));
6✔
140
        } catch (IllegalArgumentException ex) {
×
141
            logger.error("Error creating IRI from user string: {}", entry.get("user"), ex);
×
142
            return;
×
143
        }
1✔
144
        String pubkeyhash = entry.get("pubkeyHash");
4✔
145
        boolean approved = approvedIdPubkeyhashMap.containsKey(userIri) && approvedIdPubkeyhashMap.get(userIri).contains(pubkeyhash);
17✔
146
        boolean authoritative = "true".equals(entry.get("authoritative"));
6✔
147
        IRI introNpIri = null;
2✔
148
        try {
149
            introNpIri = vf.createIRI(entry.get("intronp"));
6✔
150
        } catch (IllegalArgumentException ex) {
×
151
            logger.error("Error creating IRI from intronp string: {}", entry.get("intronp"), ex);
×
152
        }
1✔
153
        IRI keyLocation = null;
2✔
154
        try {
155
            if (!entry.get("keyLocation").isEmpty()) {
5✔
156
                keyLocation = vf.createIRI(entry.get("keyLocation"));
6✔
157
            }
158
        } catch (IllegalArgumentException ex) {
×
159
            logger.error("Error creating IRI from keyLocation string: {}", entry.get("keyLocation"), ex);
×
160
        }
1✔
161
        if (approved) {
2✔
162
            if (authoritative) {
2✔
163
                if (introNpIri != null) approvedIntros.add(introNpIri);
7!
164
                if (keyLocation != null) addValue(approvedPubkeyhashLocationMap, pubkeyhash, keyLocation);
9✔
165
            }
166
        } else {
167
            addValue(unapprovedIdPubkeyhashMap, userIri, entry.get("pubkeyHash"));
8✔
168
            addValue(unapprovedPubkeyhashIdMap, entry.get("pubkeyHash"), userIri);
8✔
169
            if (keyLocation != null) addValue(unapprovedPubkeyhashLocationMap, pubkeyhash, keyLocation);
8✔
170
        }
171
        if (introNpIri != null) {
2!
172
            addValue(pubkeyhashIntroMap, entry.get("pubkeyHash"), introNpIri);
8✔
173
        }
174
        String name = entry.get("name");
4✔
175
        if (!name.isEmpty() && !idNameMap.containsKey(userIri)) {
8✔
176
            idNameMap.put(userIri, name);
6✔
177
        }
178
    }
1✔
179

180
/*
181
    private void register(String npId, boolean approved) {
182
        if (!TrustyUriUtils.isPotentialTrustyUri(npId)) return;
183
        IntroNanopub introNp = toIntroNanopub(npId);
184
        if (introNp == null) {
185
            //logger.error("No latest version of introduction found");
186
            return;
187
        }
188
        if (introNp.getUser() == null) {
189
            //logger.error("No identifier found in introduction");
190
            return;
191
        }
192
        if (introNp.getKeyDeclarations().isEmpty()) {
193
            //logger.error("No key declarations found in introduction");
194
            return;
195
        }
196
        if (approved) {
197
            approvedIntroMap.put(introNp.getNanopub().getUri(), introNp);
198
        }
199
        String userId = introNp.getUser().stringValue();
200
        IRI userIri = Utils.vf.createIRI(userId);
201
        if (userId.startsWith("https://orcid.org/")) {
202
            // Some simple ORCID ID wellformedness check:
203
            if (!userId.matches("https://orcid.org/[0-9]{4}-[0-9]{4}-[0-9]{4}-[0-9]{3}[0-9X]")) return;
204
        }
205
        for (KeyDeclaration kd : introNp.getKeyDeclarations()) {
206
            String pubkey = kd.getPublicKeyString();
207
            IRI keyLocation = kd.getKeyLocation();
208
            if (approved) {
209
                addValue(approvedIdPubkeyMap, userIri, pubkey);
210
                addValue(approvedPubkeyIdMap, pubkey, userIri);
211
                if (keyLocation != null) addValue(approvedPubkeyLocationMap, pubkey, keyLocation);
212
            } else {
213
                if (!hasValue(approvedIdPubkeyMap, userIri, pubkey)) {
214
                    addValue(unapprovedIdPubkeyMap, userIri, pubkey);
215
                    addValue(unapprovedPubkeyIdMap, pubkey, userIri);
216
                    if (keyLocation != null) addValue(unapprovedPubkeyLocationMap, pubkey, keyLocation);
217
                }
218
                addValue(pubkeyIntroMap, pubkey, introNp.getNanopub().getUri());
219
            }
220
        }
221
        if (!idNameMap.containsKey(userIri)) {
222
            idNameMap.put(userIri, introNp.getName());
223
        }
224
    }
225
    */
226

227
    private void addValue(Map<IRI, Set<String>> map, IRI key, String value) {
228
        Set<String> values = map.get(key);
5✔
229
        if (values == null) {
2✔
230
            values = new HashSet<>();
4✔
231
            map.put(key, values);
5✔
232
        }
233
        values.add(value);
4✔
234
    }
1✔
235

236
    private void addValue(Map<String, Set<IRI>> map, String key, IRI value) {
237
        Set<IRI> values = map.get(key);
5✔
238
        if (values == null) {
2✔
239
            values = new HashSet<>();
4✔
240
            map.put(key, values);
5✔
241
        }
242
        values.add(value);
4✔
243
    }
1✔
244

245
    private boolean hasValue(Map<IRI, Set<String>> map, IRI key, String value) {
246
        Set<String> values = map.get(key);
×
247
        if (values == null) return false;
×
248
        return values.contains(value);
×
249
    }
250

251
//        private static boolean hasValue(Map<String,Set<IRI>> map, String key, IRI value) {
252
//                Set<IRI> values = map.get(key);
253
//                if (values == null) return false;
254
//                return values.contains(value);
255
//        }
256

257
    /**
258
     * Checks if the given IRI is a user identifier.
259
     *
260
     * @param userIri the IRI to check
261
     * @return true if the IRI is a user identifier, false otherwise
262
     */
263
    public boolean isUser(IRI userIri) {
264
        return approvedIdPubkeyhashMap.containsKey(userIri) || unapprovedIdPubkeyhashMap.containsKey(userIri);
×
265
    }
266

267
    /**
268
     * Checks if the given userId is a valid user identifier.
269
     *
270
     * @param userId the user identifier to check, must start with "https://" or "http://"
271
     * @return true if the userId is a valid user identifier, false otherwise
272
     */
273
    public boolean isUser(String userId) {
274
        if (!userId.startsWith("https://") && !userId.startsWith("http://")) return false;
×
275
        try {
276
            IRI userIri = Utils.vf.createIRI(userId);
×
277
            return approvedIdPubkeyhashMap.containsKey(userIri) || unapprovedIdPubkeyhashMap.containsKey(userIri);
×
278
        } catch (IllegalArgumentException ex) {
×
279
            return false;
×
280
        }
281
    }
282

283
    /**
284
     * Checks if the given public key is approved for the specified user.
285
     *
286
     * @param pubkeyhash the public key to check
287
     * @param user       the IRI of the user to check against
288
     * @return true if the key is approved for the user, false otherwise
289
     */
290
    public boolean isApprovedPubkeyhashForUser(String pubkeyhash, IRI user) {
291
        return hasValue(approvedIdPubkeyhashMap, user, pubkeyhash);
×
292
    }
293

294
    private String getShortName(IRI userIri) {
295
        if (userIri == null) return "(unknown)";
×
296
        String n = userIri.stringValue();
×
297
        n = n.replaceFirst("^https://orcid.org/", "");
×
298
        if (n.length() > 40) return n.substring(0, 30) + "...";
×
299
        return n;
×
300
    }
301

302
    /**
303
     * Retrieves the IRI of a user based on their public key.
304
     *
305
     * @param pubkeyHash   the public key of the user
306
     * @param approvedOnly if true, only approved users are considered; if false, unapproved users are also considered
307
     * @return the IRI of the user if found, or null if not found
308
     */
309
    public IRI getUserIriForPubkeyhash(String pubkeyHash, boolean approvedOnly) {
310
        Set<IRI> userIris = approvedPubkeyhashIdMap.get(pubkeyHash);
×
311
        if (userIris != null && userIris.size() == 1) return userIris.iterator().next();
×
312
        if (!approvedOnly) {
×
313
            userIris = unapprovedPubkeyhashIdMap.get(pubkeyHash);
×
314
            if (userIris != null && userIris.size() == 1) return userIris.iterator().next();
×
315
        }
316
        return null;
×
317
    }
318

319
    public IRI getSignatureOwnerIri(Nanopub np) {
320
        try {
321
            if (np != null) {
2!
322
                NanopubSignatureElement se = SignatureUtils.getSignatureElement(np);
3✔
323
                if (se != null) {
2!
324
                    String pubkeyhash = Utils.createSha256HexHash(se.getPublicKeyString());
×
325
                    return getUserIriForPubkeyhash(pubkeyhash, true);
×
326
                }
327
            }
328
        } catch (MalformedCryptoElementException ex) {
×
329
            logger.error("Error getting signature element", ex);
×
330
        }
1✔
331
        return null;
2✔
332
    }
333

334
    /**
335
     * Retrieves the name of a user based on their IRI.
336
     *
337
     * @param userIri the IRI of the user
338
     * @return the name of the user if found, or null if not found
339
     */
340
    public String getName(IRI userIri) {
341
        return idNameMap.get(userIri);
6✔
342
    }
343

344
    /**
345
     * Retrieves the display name of a user based on their IRI.
346
     *
347
     * @param userIri the IRI of the user
348
     * @return the display name of the user, which includes their name and short name
349
     */
350
    public String getDisplayName(IRI userIri) {
351
        String name = getName(userIri);
×
352
        if (name != null && !name.isEmpty()) {
×
353
            return name + " (" + getShortName(userIri) + ")";
×
354
        }
355
        return getShortName(userIri);
×
356
    }
357

358
    /**
359
     * Retrieves a short display name for a user based on their IRI.
360
     *
361
     * @param userIri the IRI of the user
362
     * @return the short display name of the user, which is either their name or their short name
363
     */
364
    public String getShortDisplayName(IRI userIri) {
365
        String name = getName(userIri);
×
366
        if (name != null && !name.isEmpty()) {
×
367
            return name;
×
368
        }
369
        return getShortName(userIri);
×
370
    }
371

372
    /**
373
     * Retrieves a short display name for a user based on their IRI and public key.
374
     *
375
     * @param userIri    the IRI of the user
376
     * @param pubkeyhash the public key of the user
377
     * @return the short display name of the user, which may include a contested identity note if multiple identities are associated with the public key
378
     */
379
    public String getShortDisplayNameForPubkeyhash(IRI userIri, String pubkeyhash) {
380
        Set<IRI> ids = approvedPubkeyhashIdMap.get(pubkeyhash);
×
381
        if (ids == null || ids.isEmpty()) {
×
382
            ids = unapprovedPubkeyhashIdMap.get(pubkeyhash);
×
383
            if (ids == null || ids.isEmpty()) {
×
384
                return getShortName(userIri);
×
385
            } else if (ids.size() == 1) {
×
386
                return getShortDisplayName(ids.iterator().next());
×
387
            } else {
388
                return getShortName(userIri) + " (contested identity)";
×
389
            }
390
        } else if (ids.size() == 1) {
×
391
            return getShortDisplayName(ids.iterator().next());
×
392
        } else {
393
            return "(contested identity)";
×
394
        }
395
    }
396

397
    /**
398
     * Finds a single user ID for a given public key.
399
     *
400
     * @param pubkeyhash the public key to search for
401
     * @return the IRI of the user if exactly one ID is found for the public key, or null if no ID or multiple IDs are found
402
     */
403
    public IRI findSingleIdForPubkeyhash(String pubkeyhash) {
404
        if (approvedPubkeyhashIdMap.containsKey(pubkeyhash) && !approvedPubkeyhashIdMap.get(pubkeyhash).isEmpty()) {
×
405
            if (approvedPubkeyhashIdMap.get(pubkeyhash).size() == 1) {
×
406
                return approvedPubkeyhashIdMap.get(pubkeyhash).iterator().next();
×
407
            } else {
408
                return null;
×
409
            }
410
        }
411
        if (unapprovedPubkeyhashIdMap.containsKey(pubkeyhash) && !unapprovedPubkeyhashIdMap.get(pubkeyhash).isEmpty()) {
×
412
            if (unapprovedPubkeyhashIdMap.get(pubkeyhash).size() == 1) {
×
413
                return unapprovedPubkeyhashIdMap.get(pubkeyhash).iterator().next();
×
414
            } else {
415
                return null;
×
416
            }
417
        }
418
        return null;
×
419
    }
420

421
    public final transient Comparator<IRI> userComparator = (iri1, iri2) -> getDisplayName(iri1).toLowerCase().compareTo(getDisplayName(iri2).toLowerCase());
4✔
422

423
    /**
424
     * Retrieves a list of users, either approved or unapproved.
425
     *
426
     * @param approved if true, retrieves approved users; if false, retrieves unapproved users
427
     * @return a sorted list of user IRIs
428
     */
429
    public List<IRI> getUsers(boolean approved) {
430
        List<IRI> list;
431
        if (approved) {
×
432
            list = new ArrayList<IRI>(approvedIdPubkeyhashMap.keySet());
×
433
        } else {
434
            list = new ArrayList<IRI>();
×
435
            for (IRI u : unapprovedIdPubkeyhashMap.keySet()) {
×
436
                if (!approvedIdPubkeyhashMap.containsKey(u)) list.add(u);
×
437
            }
×
438
        }
439
        // TODO Cache the sorted list to not sort from scratch each time:
440
        list.sort(userComparator);
×
441
        return list;
×
442
    }
443

444
    /**
445
     * Retrieves a list of public keys for a given user.
446
     *
447
     * @param user     the IRI of the user whose public keys are to be retrieved
448
     * @param approved if true, retrieves approved public keys; if false, retrieves unapproved public keys
449
     * @return a list of public keys associated with the user, either approved or unapproved
450
     */
451
    public List<String> getPubkeyhashes(IRI user, Boolean approved) {
452
        List<String> pubkeys = new ArrayList<>();
×
453
        if (user != null) {
×
454
            if (approved == null || approved) {
×
455
                if (approvedIdPubkeyhashMap.containsKey(user)) pubkeys.addAll(approvedIdPubkeyhashMap.get(user));
×
456
            }
457
            if (approved == null || !approved) {
×
458
                if (unapprovedIdPubkeyhashMap.containsKey(user)) pubkeys.addAll(unapprovedIdPubkeyhashMap.get(user));
×
459
            }
460
        }
461
        return pubkeys;
×
462
    }
463

464
    /**
465
     * Retrieves a list of introduction nanopublications for a given user.
466
     *
467
     * @param user the IRI of the user whose introduction nanopublications are to be retrieved
468
     * @return a list of introduction nanopublications associated with the user, sorted by creation time
469
     */
470
    public List<IntroNanopub> getIntroNanopubs(IRI user) {
471
        if (introNanopubLists.containsKey(user)) return introNanopubLists.get(user);
×
472

473
        Map<IRI, IntroNanopub> introNps = new HashMap<>();
×
474
        if (approvedIdPubkeyhashMap.containsKey(user)) {
×
475
            for (String pk : approvedIdPubkeyhashMap.get(user)) {
×
476
                getIntroNanopubs(pk, introNps);
×
477
            }
×
478
        }
479
        if (unapprovedIdPubkeyhashMap.containsKey(user)) {
×
480
            for (String pk : unapprovedIdPubkeyhashMap.get(user)) {
×
481
                getIntroNanopubs(pk, introNps);
×
482
            }
×
483
        }
484
        List<IntroNanopub> list = new ArrayList<>(introNps.values());
×
485
        list.sort((i0, i1) -> {
×
486
            Calendar c0 = SimpleTimestampPattern.getCreationTime(i0.getNanopub());
×
487
            Calendar c1 = SimpleTimestampPattern.getCreationTime(i1.getNanopub());
×
488
            if (c0 == null && c1 == null) return 0;
×
489
            if (c0 == null) return 1;
×
490
            if (c1 == null) return -1;
×
491
            return -c0.compareTo(c1);
×
492
        });
493
        introNanopubLists.put(user, list);
×
494
        return list;
×
495
    }
496

497
    /**
498
     * Retrieves a map of introduction nanopublications for a given public key.
499
     *
500
     * @param pubkey the public key for which introduction nanopublications are to be retrieved
501
     * @return a map where the keys are IRI identifiers of introduction nanopublications and the values are the corresponding IntroNanopub objects
502
     */
503
    public Map<IRI, IntroNanopub> getIntroNanopubs(String pubkey) {
504
        Map<IRI, IntroNanopub> introNps = new HashMap<>();
×
505
        getIntroNanopubs(pubkey, introNps);
×
506
        return introNps;
×
507
    }
508

509
    private void getIntroNanopubs(String pubkeyhash, Map<IRI, IntroNanopub> introNps) {
510
        if (pubkeyhashIntroMap.containsKey(pubkeyhash)) {
×
511
            for (IRI iri : pubkeyhashIntroMap.get(pubkeyhash)) {
×
512
                IntroNanopub introNp = toIntroNanopub(iri);
×
513
                if (introNp != null) {
×
514
                    introNps.put(iri, introNp);
×
515
                }
516
            }
×
517
        }
518
    }
×
519

520
    /**
521
     * Checks if the given introduction nanopublication is approved.
522
     *
523
     * @param in the introduction nanopublication to check
524
     * @return true if the introduction nanopublication is approved, false otherwise
525
     */
526
    public boolean isApproved(IntroNanopub in) {
527
        return approvedIntros.contains(in.getNanopub().getUri());
×
528
    }
529

530
    /**
531
     * Retrieves the location of a public key.
532
     *
533
     * @param pubkeyhash the public key for which the location is to be retrieved
534
     * @return the IRI of the key location if found, or null if not found or if multiple locations are associated with the key
535
     */
536
    public IRI getKeyLocationForPubkeyhash(String pubkeyhash) {
537
        if (approvedPubkeyhashLocationMap.containsKey(pubkeyhash) && !approvedPubkeyhashLocationMap.get(pubkeyhash).isEmpty()) {
×
538
            if (approvedPubkeyhashLocationMap.get(pubkeyhash).size() == 1)
×
539
                return approvedPubkeyhashLocationMap.get(pubkeyhash).iterator().next();
×
540
            return null;
×
541
        }
542
        if (unapprovedPubkeyhashLocationMap.containsKey(pubkeyhash) && unapprovedPubkeyhashLocationMap.get(pubkeyhash).size() == 1) {
×
543
            return unapprovedPubkeyhashLocationMap.get(pubkeyhash).iterator().next();
×
544
        }
545
        return null;
×
546
    }
547

548
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc