/** * Creates a new instance from a valid hash string. * * @param hash the hash to generate the {@link DescriptorDigest} from * @return a new {@link DescriptorDigest} created from the hash * @throws DigestException if the hash is invalid */ public static DescriptorDigest fromHash(String hash) throws DigestException { if (!hash.matches(HASH_REGEX)) { throw new DigestException("Invalid hash: " + hash); } return new DescriptorDigest(hash); }
@Override public DescriptorDigest handleResponse(Response response) throws IOException { // Checks if the image digest is as expected. DescriptorDigest expectedDigest = JsonTemplateMapper.toBlob(manifestTemplate) .writeTo(ByteStreams.nullOutputStream()) .getDigest(); List<String> receivedDigests = response.getHeader(RESPONSE_DIGEST_HEADER); if (receivedDigests.size() == 1) { try { DescriptorDigest receivedDigest = DescriptorDigest.fromDigest(receivedDigests.get(0)); if (expectedDigest.equals(receivedDigest)) { return expectedDigest; } } catch (DigestException ex) { // Invalid digest. } } // The received digest is not as expected. Warns about this. eventDispatcher.dispatch( LogEvent.warn(makeUnexpectedImageDigestWarning(expectedDigest, receivedDigests))); return expectedDigest; }
/** * Gets the filename for the layer file. The filename is in the form {@code <layer diff * ID>.layer}. * * @param layerDiffId the layer's diff ID * @return the layer filename */ String getLayerFilename(DescriptorDigest layerDiffId) { return layerDiffId.getHash(); }
/** * Gets the diff ID portion of the layer filename. * * @param layerFile the layer file to parse for the diff ID * @return the diff ID portion of the layer file filename * @throws CacheCorruptedException if no valid diff ID could be parsed */ static DescriptorDigest getDiffId(Path layerFile) throws CacheCorruptedException { try { String diffId = layerFile.getFileName().toString(); return DescriptorDigest.fromHash(diffId); } catch (DigestException | IndexOutOfBoundsException ex) { throw new CacheCorruptedException( "Layer file did not include valid diff ID: " + layerFile, ex); } }
@Override public void serialize( DescriptorDigest value, JsonGenerator jsonGenerator, SerializerProvider ignored) throws IOException { jsonGenerator.writeString(value.toString()); } }
@Override public int hashCode() { int result = digest.hashCode(); result = 31 * result + (int) (size ^ (size >>> 32)); return result; }
@Override public DescriptorDigest deserialize(JsonParser jsonParser, DeserializationContext ignored) throws IOException { try { return DescriptorDigest.fromDigest(jsonParser.getValueAsString()); } catch (DigestException ex) { throw new IOException(ex); } } }
/** * Resolves a selector file. * * @param selector the selector digest * @return the selector file */ Path getSelectorFile(DescriptorDigest selector) { return cacheDirectory.resolve(SELECTORS_DIRECTORY).resolve(selector.getHash()); }
/** * Lists all the layer digests stored. * * @return the list of layer digests * @throws CacheCorruptedException if the cache was found to be corrupted * @throws IOException if an I/O exception occurs */ Set<DescriptorDigest> fetchDigests() throws IOException, CacheCorruptedException { try (Stream<Path> layerDirectories = Files.list(defaultCacheStorageFiles.getLayersDirectory())) { List<Path> layerDirectoriesList = layerDirectories.collect(Collectors.toList()); Set<DescriptorDigest> layerDigests = new HashSet<>(layerDirectoriesList.size()); for (Path layerDirectory : layerDirectoriesList) { try { layerDigests.add(DescriptorDigest.fromHash(layerDirectory.getFileName().toString())); } catch (DigestException ex) { throw new CacheCorruptedException("Found non-digest file in layers directory", ex); } } return layerDigests; } }
@Override public void serialize( DescriptorDigest value, JsonGenerator jsonGenerator, SerializerProvider ignored) throws IOException { jsonGenerator.writeString(value.toString()); } }
@Override public int hashCode() { int result = digest.hashCode(); result = 31 * result + (int) (size ^ (size >>> 32)); return result; }
@Override public DescriptorDigest deserialize(JsonParser jsonParser, DeserializationContext ignored) throws IOException { try { return DescriptorDigest.fromDigest(jsonParser.getValueAsString()); } catch (DigestException ex) { throw new IOException(ex); } } }
/** * Gets the directory for the layer with digest {@code layerDigest}. * * @param layerDigest the digest of the layer * @return the directory for that {@code layerDigest} */ Path getLayerDirectory(DescriptorDigest layerDigest) { return getLayersDirectory().resolve(layerDigest.getHash()); }
@Override public DescriptorDigest handleResponse(Response response) throws IOException { // Checks if the image digest is as expected. DescriptorDigest expectedDigest = JsonTemplateMapper.toBlob(manifestTemplate) .writeTo(ByteStreams.nullOutputStream()) .getDigest(); List<String> receivedDigests = response.getHeader(RESPONSE_DIGEST_HEADER); if (receivedDigests.size() == 1) { try { DescriptorDigest receivedDigest = DescriptorDigest.fromDigest(receivedDigests.get(0)); if (expectedDigest.equals(receivedDigest)) { return expectedDigest; } } catch (DigestException ex) { // Invalid digest. } } // The received digest is not as expected. Warns about this. eventDispatcher.dispatch( LogEvent.warn(makeUnexpectedImageDigestWarning(expectedDigest, receivedDigests))); return expectedDigest; }
/** * Builds a {@link BlobDescriptor} with the hash and size of the bytes written. The buffer resets * after this method is called, so this method should only be called once per BlobDescriptor. * * @return the built {@link BlobDescriptor}. */ public BlobDescriptor toBlobDescriptor() { try { byte[] hashedBytes = digest.digest(); // Encodes each hashed byte into 2-character hexadecimal representation. StringBuilder stringBuilder = new StringBuilder(2 * hashedBytes.length); for (byte b : hashedBytes) { stringBuilder.append(String.format("%02x", b)); } String hash = stringBuilder.toString(); DescriptorDigest digest = DescriptorDigest.fromHash(hash); return new BlobDescriptor(totalBytes, digest); } catch (DigestException ex) { throw new RuntimeException("SHA-256 algorithm produced invalid hash: " + ex.getMessage(), ex); } }