Skip to content

Commit 1072947

Browse files
authored
Merge pull request #827 from sigstore/adjust-fetcher
Separate meta fetching from target fetching
2 parents 8628fc0 + 5ab1916 commit 1072947

File tree

8 files changed

+126
-124
lines changed

8 files changed

+126
-124
lines changed
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
/*
2+
* Copyright 2024 The Sigstore Authors.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
package dev.sigstore.tuf;
17+
18+
import java.io.IOException;
19+
20+
public interface Fetcher {
21+
22+
String getSource();
23+
24+
byte[] fetchResource(String filename, int maxLength)
25+
throws IOException, FileExceedsMaxLengthException;
26+
}

sigstore-java/src/main/java/dev/sigstore/tuf/FileSystemTufStore.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -53,7 +53,7 @@ public static MutableTufStore newFileSystemStore(Path repoBaseDir) throws IOExce
5353
return newFileSystemStore(repoBaseDir, defaultTargetsCache);
5454
}
5555

56-
static MutableTufStore newFileSystemStore(Path repoBaseDir, Path targetsCache) {
56+
public static MutableTufStore newFileSystemStore(Path repoBaseDir, Path targetsCache) {
5757
if (!Files.isDirectory(repoBaseDir)) {
5858
throw new IllegalArgumentException(repoBaseDir + " must be a file system directory.");
5959
}

sigstore-java/src/main/java/dev/sigstore/tuf/HttpMetaFetcher.java renamed to sigstore-java/src/main/java/dev/sigstore/tuf/HttpFetcher.java

Lines changed: 6 additions & 56 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2022 The Sigstore Authors.
2+
* Copyright 2024 The Sigstore Authors.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -15,85 +15,35 @@
1515
*/
1616
package dev.sigstore.tuf;
1717

18-
import static dev.sigstore.json.GsonSupplier.GSON;
19-
2018
import com.google.api.client.http.GenericUrl;
2119
import com.google.api.client.json.gson.GsonFactory;
22-
import com.google.common.base.Preconditions;
2320
import dev.sigstore.http.HttpClients;
2421
import dev.sigstore.http.ImmutableHttpParams;
25-
import dev.sigstore.tuf.model.Root;
26-
import dev.sigstore.tuf.model.SignedTufMeta;
27-
import dev.sigstore.tuf.model.TufMeta;
2822
import java.io.IOException;
2923
import java.net.MalformedURLException;
3024
import java.net.URL;
31-
import java.nio.charset.StandardCharsets;
3225
import java.util.Locale;
33-
import java.util.Optional;
34-
import javax.annotation.Nullable;
3526

36-
public class HttpMetaFetcher implements MetaFetcher {
27+
public class HttpFetcher implements Fetcher {
3728

38-
private static final int MAX_META_BYTES = 99 * 1024; // 99 KB
3929
private final URL mirror;
4030

41-
HttpMetaFetcher(URL mirror) {
31+
private HttpFetcher(URL mirror) {
4232
this.mirror = mirror;
4333
}
4434

45-
public static HttpMetaFetcher newFetcher(URL mirror) throws MalformedURLException {
35+
public static HttpFetcher newFetcher(URL mirror) throws MalformedURLException {
4636
if (mirror.toString().endsWith("/")) {
47-
return new HttpMetaFetcher(mirror);
37+
return new HttpFetcher(mirror);
4838
}
49-
return new HttpMetaFetcher(new URL(mirror.toExternalForm() + "/"));
39+
return new HttpFetcher(new URL(mirror.toExternalForm() + "/"));
5040
}
5141

5242
@Override
5343
public String getSource() {
5444
return mirror.toString();
5545
}
5646

57-
@Override
58-
public Optional<MetaFetchResult<Root>> getRootAtVersion(int version)
59-
throws IOException, FileExceedsMaxLengthException {
60-
String versionFileName = version + ".root.json";
61-
return getMeta(versionFileName, Root.class, null);
62-
}
63-
64-
@Override
65-
public <T extends SignedTufMeta<? extends TufMeta>> Optional<MetaFetchResult<T>> getMeta(
66-
String role, Class<T> t) throws IOException, FileExceedsMaxLengthException {
67-
return getMeta(getFileName(role, null), t, null);
68-
}
69-
70-
@Override
71-
public <T extends SignedTufMeta<? extends TufMeta>> Optional<MetaFetchResult<T>> getMeta(
72-
String role, int version, Class<T> t, Integer maxSize)
73-
throws IOException, FileExceedsMaxLengthException {
74-
Preconditions.checkArgument(version > 0, "version should be positive, got: %s", version);
75-
return getMeta(getFileName(role, version), t, maxSize);
76-
}
77-
78-
private static String getFileName(String role, @Nullable Integer version) {
79-
return version == null
80-
? role + ".json"
81-
: String.format(Locale.ROOT, "%d.%s.json", version, role);
82-
}
83-
84-
<T extends SignedTufMeta> Optional<MetaFetchResult<T>> getMeta(
85-
String filename, Class<T> t, Integer maxSize)
86-
throws IOException, FileExceedsMaxLengthException {
87-
byte[] roleBytes = fetchResource(filename, maxSize == null ? MAX_META_BYTES : maxSize);
88-
if (roleBytes == null) {
89-
return Optional.empty();
90-
}
91-
var result =
92-
new MetaFetchResult<T>(
93-
roleBytes, GSON.get().fromJson(new String(roleBytes, StandardCharsets.UTF_8), t));
94-
return Optional.of(result);
95-
}
96-
9747
@Override
9848
public byte[] fetchResource(String filename, int maxLength)
9949
throws IOException, FileExceedsMaxLengthException {

sigstore-java/src/main/java/dev/sigstore/tuf/MetaFetcher.java

Lines changed: 54 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -15,59 +15,69 @@
1515
*/
1616
package dev.sigstore.tuf;
1717

18+
import static dev.sigstore.json.GsonSupplier.GSON;
19+
20+
import com.google.common.base.Preconditions;
1821
import dev.sigstore.tuf.model.Root;
1922
import dev.sigstore.tuf.model.SignedTufMeta;
2023
import dev.sigstore.tuf.model.TufMeta;
2124
import java.io.IOException;
25+
import java.nio.charset.StandardCharsets;
26+
import java.util.Locale;
2227
import java.util.Optional;
28+
import javax.annotation.Nullable;
2329

24-
/** Retrieves TUF metadata. */
25-
public interface MetaFetcher {
30+
public class MetaFetcher {
2631

27-
/**
28-
* Describes the source of the metadata being fetched from. e.g "http://mirror.bla/mirror",
29-
* "mock", "c:/tmp".
30-
*/
31-
String getSource();
32+
private static final int MAX_META_BYTES = 99 * 1024; // 99 KB
33+
private final Fetcher fetcher;
3234

33-
/**
34-
* Fetch the {@link Root} at the specified {@code version}.
35-
*
36-
* @throws FileExceedsMaxLengthException when the retrieved file is larger than the maximum
37-
* allowed by the client
38-
*/
39-
Optional<MetaFetchResult<Root>> getRootAtVersion(int version)
40-
throws IOException, FileExceedsMaxLengthException;
35+
private MetaFetcher(Fetcher fetcher) {
36+
this.fetcher = fetcher;
37+
}
4138

42-
/**
43-
* Fetches the unversioned specified role meta from the source
44-
*
45-
* @param name TUF role name
46-
* @param roleType this should be the type you expect in return
47-
* @return the latest fully de-serialized role if it was present at the source
48-
* @throws IOException in case of IO errors
49-
* @throws FileExceedsMaxLengthException if the role meta at source exceeds client specified max
50-
* size
51-
*/
52-
<T extends SignedTufMeta<? extends TufMeta>> Optional<MetaFetchResult<T>> getMeta(
53-
String name, Class<T> roleType) throws IOException, FileExceedsMaxLengthException;
39+
public static MetaFetcher newFetcher(Fetcher fetcher) {
40+
return new MetaFetcher(fetcher);
41+
}
5442

55-
/**
56-
* Fetches the specified role meta from the source
57-
*
58-
* @param name TUF role name
59-
* @param version the version of the file to download
60-
* @param roleType this should be the type you expect in return
61-
* @param maxSize max file size in bytes
62-
* @return the fully de-serialized role if it was present at the source
63-
* @throws IOException in case of IO errors
64-
* @throws FileExceedsMaxLengthException if the role meta at source exceeds client specified max
65-
* size
66-
*/
67-
<T extends SignedTufMeta<? extends TufMeta>> Optional<MetaFetchResult<T>> getMeta(
68-
String name, int version, Class<T> roleType, Integer maxSize)
69-
throws IOException, FileExceedsMaxLengthException;
43+
public String getSource() {
44+
return fetcher.getSource();
45+
}
46+
47+
public Optional<MetaFetchResult<Root>> getRootAtVersion(int version)
48+
throws IOException, FileExceedsMaxLengthException {
49+
String versionFileName = version + ".root.json";
50+
return getMeta(versionFileName, Root.class, null);
51+
}
7052

71-
byte[] fetchResource(String filename, int maxLength)
72-
throws IOException, FileExceedsMaxLengthException;
53+
public <T extends SignedTufMeta<? extends TufMeta>> Optional<MetaFetchResult<T>> getMeta(
54+
String role, Class<T> t) throws IOException, FileExceedsMaxLengthException {
55+
return getMeta(getFileName(role, null), t, null);
56+
}
57+
58+
public <T extends SignedTufMeta<? extends TufMeta>> Optional<MetaFetchResult<T>> getMeta(
59+
String role, int version, Class<T> t, Integer maxSize)
60+
throws IOException, FileExceedsMaxLengthException {
61+
Preconditions.checkArgument(version > 0, "version should be positive, got: %s", version);
62+
return getMeta(getFileName(role, version), t, maxSize);
63+
}
64+
65+
private static String getFileName(String role, @Nullable Integer version) {
66+
return version == null
67+
? role + ".json"
68+
: String.format(Locale.ROOT, "%d.%s.json", version, role);
69+
}
70+
71+
<T extends SignedTufMeta<? extends TufMeta>> Optional<MetaFetchResult<T>> getMeta(
72+
String filename, Class<T> t, Integer maxSize)
73+
throws IOException, FileExceedsMaxLengthException {
74+
byte[] roleBytes = fetcher.fetchResource(filename, maxSize == null ? MAX_META_BYTES : maxSize);
75+
if (roleBytes == null) {
76+
return Optional.empty();
77+
}
78+
var result =
79+
new MetaFetchResult<T>(
80+
roleBytes, GSON.get().fromJson(new String(roleBytes, StandardCharsets.UTF_8), t));
81+
return Optional.of(result);
82+
}
7383
}

sigstore-java/src/main/java/dev/sigstore/tuf/SigstoreTufClient.java

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -75,7 +75,7 @@ public Builder usePublicGoodInstance() {
7575
}
7676
try {
7777
tufMirror(
78-
new URL("https://tuf-repo-cdn.sigstore.dev"),
78+
new URL("https://tuf-repo-cdn.sigstore.dev/"),
7979
RootProvider.fromResource(PUBLIC_GOOD_ROOT_RESOURCE));
8080
} catch (MalformedURLException e) {
8181
throw new AssertionError(e);
@@ -126,11 +126,18 @@ public SigstoreTufClient build() throws IOException {
126126
if (!Files.isDirectory(tufCacheLocation)) {
127127
Files.createDirectories(tufCacheLocation);
128128
}
129+
var normalizedRemoteMirror =
130+
remoteMirror.toString().endsWith("/")
131+
? remoteMirror
132+
: new URL(remoteMirror.toExternalForm() + "/");
133+
var targetsLocation = new URL(normalizedRemoteMirror.toExternalForm() + "targets");
129134
var tufUpdater =
130135
Updater.builder()
131136
.setTrustedRootPath(trustedRoot)
132137
.setLocalStore(FileSystemTufStore.newFileSystemStore(tufCacheLocation))
133-
.setFetcher(HttpMetaFetcher.newFetcher(remoteMirror))
138+
.setMetaFetcher(
139+
MetaFetcher.newFetcher(HttpFetcher.newFetcher(normalizedRemoteMirror)))
140+
.setTargetFetcher(HttpFetcher.newFetcher(targetsLocation))
134141
.build();
135142
return new SigstoreTufClient(tufUpdater, cacheValidity);
136143
}

0 commit comments

Comments
 (0)