Skip to content

Commit

Permalink
Separate meta fetching from target fetching
Browse files Browse the repository at this point in the history
Signed-off-by: Appu Goundan <[email protected]>
  • Loading branch information
loosebazooka committed Oct 10, 2024
1 parent 8628fc0 commit 5ab1916
Show file tree
Hide file tree
Showing 8 changed files with 126 additions and 124 deletions.
26 changes: 26 additions & 0 deletions sigstore-java/src/main/java/dev/sigstore/tuf/Fetcher.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
/*
* Copyright 2024 The Sigstore Authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package dev.sigstore.tuf;

import java.io.IOException;

public interface Fetcher {

String getSource();

byte[] fetchResource(String filename, int maxLength)
throws IOException, FileExceedsMaxLengthException;
}
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,7 @@ public static MutableTufStore newFileSystemStore(Path repoBaseDir) throws IOExce
return newFileSystemStore(repoBaseDir, defaultTargetsCache);
}

static MutableTufStore newFileSystemStore(Path repoBaseDir, Path targetsCache) {
public static MutableTufStore newFileSystemStore(Path repoBaseDir, Path targetsCache) {
if (!Files.isDirectory(repoBaseDir)) {
throw new IllegalArgumentException(repoBaseDir + " must be a file system directory.");
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright 2022 The Sigstore Authors.
* Copyright 2024 The Sigstore Authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
Expand All @@ -15,85 +15,35 @@
*/
package dev.sigstore.tuf;

import static dev.sigstore.json.GsonSupplier.GSON;

import com.google.api.client.http.GenericUrl;
import com.google.api.client.json.gson.GsonFactory;
import com.google.common.base.Preconditions;
import dev.sigstore.http.HttpClients;
import dev.sigstore.http.ImmutableHttpParams;
import dev.sigstore.tuf.model.Root;
import dev.sigstore.tuf.model.SignedTufMeta;
import dev.sigstore.tuf.model.TufMeta;
import java.io.IOException;
import java.net.MalformedURLException;
import java.net.URL;
import java.nio.charset.StandardCharsets;
import java.util.Locale;
import java.util.Optional;
import javax.annotation.Nullable;

public class HttpMetaFetcher implements MetaFetcher {
public class HttpFetcher implements Fetcher {

private static final int MAX_META_BYTES = 99 * 1024; // 99 KB
private final URL mirror;

HttpMetaFetcher(URL mirror) {
private HttpFetcher(URL mirror) {
this.mirror = mirror;
}

public static HttpMetaFetcher newFetcher(URL mirror) throws MalformedURLException {
public static HttpFetcher newFetcher(URL mirror) throws MalformedURLException {
if (mirror.toString().endsWith("/")) {
return new HttpMetaFetcher(mirror);
return new HttpFetcher(mirror);
}
return new HttpMetaFetcher(new URL(mirror.toExternalForm() + "/"));
return new HttpFetcher(new URL(mirror.toExternalForm() + "/"));
}

@Override
public String getSource() {
return mirror.toString();
}

@Override
public Optional<MetaFetchResult<Root>> getRootAtVersion(int version)
throws IOException, FileExceedsMaxLengthException {
String versionFileName = version + ".root.json";
return getMeta(versionFileName, Root.class, null);
}

@Override
public <T extends SignedTufMeta<? extends TufMeta>> Optional<MetaFetchResult<T>> getMeta(
String role, Class<T> t) throws IOException, FileExceedsMaxLengthException {
return getMeta(getFileName(role, null), t, null);
}

@Override
public <T extends SignedTufMeta<? extends TufMeta>> Optional<MetaFetchResult<T>> getMeta(
String role, int version, Class<T> t, Integer maxSize)
throws IOException, FileExceedsMaxLengthException {
Preconditions.checkArgument(version > 0, "version should be positive, got: %s", version);
return getMeta(getFileName(role, version), t, maxSize);
}

private static String getFileName(String role, @Nullable Integer version) {
return version == null
? role + ".json"
: String.format(Locale.ROOT, "%d.%s.json", version, role);
}

<T extends SignedTufMeta> Optional<MetaFetchResult<T>> getMeta(
String filename, Class<T> t, Integer maxSize)
throws IOException, FileExceedsMaxLengthException {
byte[] roleBytes = fetchResource(filename, maxSize == null ? MAX_META_BYTES : maxSize);
if (roleBytes == null) {
return Optional.empty();
}
var result =
new MetaFetchResult<T>(
roleBytes, GSON.get().fromJson(new String(roleBytes, StandardCharsets.UTF_8), t));
return Optional.of(result);
}

@Override
public byte[] fetchResource(String filename, int maxLength)
throws IOException, FileExceedsMaxLengthException {
Expand Down
98 changes: 54 additions & 44 deletions sigstore-java/src/main/java/dev/sigstore/tuf/MetaFetcher.java
Original file line number Diff line number Diff line change
Expand Up @@ -15,59 +15,69 @@
*/
package dev.sigstore.tuf;

import static dev.sigstore.json.GsonSupplier.GSON;

import com.google.common.base.Preconditions;
import dev.sigstore.tuf.model.Root;
import dev.sigstore.tuf.model.SignedTufMeta;
import dev.sigstore.tuf.model.TufMeta;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.util.Locale;
import java.util.Optional;
import javax.annotation.Nullable;

/** Retrieves TUF metadata. */
public interface MetaFetcher {
public class MetaFetcher {

/**
* Describes the source of the metadata being fetched from. e.g "http://mirror.bla/mirror",
* "mock", "c:/tmp".
*/
String getSource();
private static final int MAX_META_BYTES = 99 * 1024; // 99 KB
private final Fetcher fetcher;

/**
* Fetch the {@link Root} at the specified {@code version}.
*
* @throws FileExceedsMaxLengthException when the retrieved file is larger than the maximum
* allowed by the client
*/
Optional<MetaFetchResult<Root>> getRootAtVersion(int version)
throws IOException, FileExceedsMaxLengthException;
private MetaFetcher(Fetcher fetcher) {
this.fetcher = fetcher;
}

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

/**
* Fetches the specified role meta from the source
*
* @param name TUF role name
* @param version the version of the file to download
* @param roleType this should be the type you expect in return
* @param maxSize max file size in bytes
* @return the fully de-serialized role if it was present at the source
* @throws IOException in case of IO errors
* @throws FileExceedsMaxLengthException if the role meta at source exceeds client specified max
* size
*/
<T extends SignedTufMeta<? extends TufMeta>> Optional<MetaFetchResult<T>> getMeta(
String name, int version, Class<T> roleType, Integer maxSize)
throws IOException, FileExceedsMaxLengthException;
public String getSource() {
return fetcher.getSource();
}

public Optional<MetaFetchResult<Root>> getRootAtVersion(int version)
throws IOException, FileExceedsMaxLengthException {
String versionFileName = version + ".root.json";
return getMeta(versionFileName, Root.class, null);
}

byte[] fetchResource(String filename, int maxLength)
throws IOException, FileExceedsMaxLengthException;
public <T extends SignedTufMeta<? extends TufMeta>> Optional<MetaFetchResult<T>> getMeta(
String role, Class<T> t) throws IOException, FileExceedsMaxLengthException {
return getMeta(getFileName(role, null), t, null);
}

public <T extends SignedTufMeta<? extends TufMeta>> Optional<MetaFetchResult<T>> getMeta(
String role, int version, Class<T> t, Integer maxSize)
throws IOException, FileExceedsMaxLengthException {
Preconditions.checkArgument(version > 0, "version should be positive, got: %s", version);
return getMeta(getFileName(role, version), t, maxSize);
}

private static String getFileName(String role, @Nullable Integer version) {
return version == null
? role + ".json"
: String.format(Locale.ROOT, "%d.%s.json", version, role);
}

<T extends SignedTufMeta<? extends TufMeta>> Optional<MetaFetchResult<T>> getMeta(
String filename, Class<T> t, Integer maxSize)
throws IOException, FileExceedsMaxLengthException {
byte[] roleBytes = fetcher.fetchResource(filename, maxSize == null ? MAX_META_BYTES : maxSize);
if (roleBytes == null) {
return Optional.empty();
}
var result =
new MetaFetchResult<T>(
roleBytes, GSON.get().fromJson(new String(roleBytes, StandardCharsets.UTF_8), t));
return Optional.of(result);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -75,7 +75,7 @@ public Builder usePublicGoodInstance() {
}
try {
tufMirror(
new URL("https://tuf-repo-cdn.sigstore.dev"),
new URL("https://tuf-repo-cdn.sigstore.dev/"),
RootProvider.fromResource(PUBLIC_GOOD_ROOT_RESOURCE));
} catch (MalformedURLException e) {
throw new AssertionError(e);
Expand Down Expand Up @@ -126,11 +126,18 @@ public SigstoreTufClient build() throws IOException {
if (!Files.isDirectory(tufCacheLocation)) {
Files.createDirectories(tufCacheLocation);
}
var normalizedRemoteMirror =
remoteMirror.toString().endsWith("/")
? remoteMirror
: new URL(remoteMirror.toExternalForm() + "/");
var targetsLocation = new URL(normalizedRemoteMirror.toExternalForm() + "targets");
var tufUpdater =
Updater.builder()
.setTrustedRootPath(trustedRoot)
.setLocalStore(FileSystemTufStore.newFileSystemStore(tufCacheLocation))
.setFetcher(HttpMetaFetcher.newFetcher(remoteMirror))
.setMetaFetcher(
MetaFetcher.newFetcher(HttpFetcher.newFetcher(normalizedRemoteMirror)))
.setTargetFetcher(HttpFetcher.newFetcher(targetsLocation))
.build();
return new SigstoreTufClient(tufUpdater, cacheValidity);
}
Expand Down
Loading

0 comments on commit 5ab1916

Please sign in to comment.