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

knowledgepixels / nanodash / 17375037963

01 Sep 2025 10:33AM UTC coverage: 11.982% (-0.04%) from 12.02%
17375037963

push

github

tkuhn
Merge branch 'master' of github.com:knowledgepixels/nanodash

330 of 3846 branches covered (8.58%)

Branch coverage included in aggregate %.

949 of 6828 relevant lines covered (13.9%)

0.61 hits per line

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

31.39
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
import java.util.concurrent.ConcurrentHashMap;
25
import java.util.concurrent.ConcurrentMap;
26

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

32
    private static final long serialVersionUID = 1L;
33

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

316
    public IRI getSignatureOwnerIri(Nanopub np) {
317
        try {
318
            if (np != null) {
2!
319
                NanopubSignatureElement se = SignatureUtils.getSignatureElement(np);
3✔
320
                if (se != null) {
2!
321
                    String pubkeyhash = Utils.createSha256HexHash(se.getPublicKeyString());
×
322
                    return getUserIriForPubkeyhash(pubkeyhash, true);
×
323
                }
324
            }
325
        } catch (MalformedCryptoElementException ex) {
×
326
            ex.printStackTrace();
×
327
        }
1✔
328
        return null;
2✔
329
    }
330

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

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

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

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

394
    /**
395
     * Finds a single user ID for a given public key.
396
     *
397
     * @param pubkeyhash the public key to search for
398
     * @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
399
     */
400
    public IRI findSingleIdForPubkeyhash(String pubkeyhash) {
401
        if (approvedPubkeyhashIdMap.containsKey(pubkeyhash) && !approvedPubkeyhashIdMap.get(pubkeyhash).isEmpty()) {
×
402
            if (approvedPubkeyhashIdMap.get(pubkeyhash).size() == 1) {
×
403
                return approvedPubkeyhashIdMap.get(pubkeyhash).iterator().next();
×
404
            } else {
405
                return null;
×
406
            }
407
        }
408
        if (unapprovedPubkeyhashIdMap.containsKey(pubkeyhash) && !unapprovedPubkeyhashIdMap.get(pubkeyhash).isEmpty()) {
×
409
            if (unapprovedPubkeyhashIdMap.get(pubkeyhash).size() == 1) {
×
410
                return unapprovedPubkeyhashIdMap.get(pubkeyhash).iterator().next();
×
411
            } else {
412
                return null;
×
413
            }
414
        }
415
        return null;
×
416
    }
417

418
    private transient Comparator<IRI> comparator = (iri1, iri2) -> getDisplayName(iri1).toLowerCase().compareTo(getDisplayName(iri2).toLowerCase());
4✔
419

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

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

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

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

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

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

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

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

545
}
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