Team Ai
Datasetpublic

codekingpro/portable-devtools

sourceHugging Faceupdated 5mo agoView on Hugging Face
1likes14kdownloads
file.js192 linesDownload Raw Back to dist
1"use strict";
2var __importDefault = (this && this.__importDefault) || function (mod) {
3    return (mod && mod.__esModule) ? mod : { "default": mod };
4};
5Object.defineProperty(exports, "__esModule", { value: true });
6exports.TargetFile = exports.MetaFile = void 0;
7const crypto_1 = __importDefault(require("crypto"));
8const util_1 = __importDefault(require("util"));
9const error_1 = require("./error");
10const utils_1 = require("./utils");
11// A container with information about a particular metadata file.
12//
13// This class is used for Timestamp and Snapshot metadata.
14class MetaFile {
15    version;
16    length;
17    hashes;
18    unrecognizedFields;
19    constructor(opts) {
20        if (opts.version <= 0) {
21            throw new error_1.ValueError('Metafile version must be at least 1');
22        }
23        if (opts.length !== undefined) {
24            validateLength(opts.length);
25        }
26        this.version = opts.version;
27        this.length = opts.length;
28        this.hashes = opts.hashes;
29        this.unrecognizedFields = opts.unrecognizedFields || {};
30    }
31    equals(other) {
32        if (!(other instanceof MetaFile)) {
33            return false;
34        }
35        return (this.version === other.version &&
36            this.length === other.length &&
37            util_1.default.isDeepStrictEqual(this.hashes, other.hashes) &&
38            util_1.default.isDeepStrictEqual(this.unrecognizedFields, other.unrecognizedFields));
39    }
40    verify(data) {
41        // Verifies that the given data matches the expected length.
42        if (this.length !== undefined) {
43            if (data.length !== this.length) {
44                throw new error_1.LengthOrHashMismatchError(`Expected length ${this.length} but got ${data.length}`);
45            }
46        }
47        // Verifies that the given data matches the supplied hashes.
48        if (this.hashes) {
49            Object.entries(this.hashes).forEach(([key, value]) => {
50                let hash;
51                try {
52                    hash = crypto_1.default.createHash(key);
53                }
54                catch (e) {
55                    throw new error_1.LengthOrHashMismatchError(`Hash algorithm ${key} not supported`);
56                }
57                const observedHash = hash.update(data).digest('hex');
58                if (observedHash !== value) {
59                    throw new error_1.LengthOrHashMismatchError(`Expected hash ${value} but got ${observedHash}`);
60                }
61            });
62        }
63    }
64    toJSON() {
65        const json = {
66            version: this.version,
67            ...this.unrecognizedFields,
68        };
69        if (this.length !== undefined) {
70            json.length = this.length;
71        }
72        if (this.hashes) {
73            json.hashes = this.hashes;
74        }
75        return json;
76    }
77    static fromJSON(data) {
78        const { version, length, hashes, ...rest } = data;
79        if (typeof version !== 'number') {
80            throw new TypeError('version must be a number');
81        }
82        if (utils_1.guard.isDefined(length) && typeof length !== 'number') {
83            throw new TypeError('length must be a number');
84        }
85        if (utils_1.guard.isDefined(hashes) && !utils_1.guard.isStringRecord(hashes)) {
86            throw new TypeError('hashes must be string keys and values');
87        }
88        return new MetaFile({
89            version,
90            length,
91            hashes,
92            unrecognizedFields: rest,
93        });
94    }
95}
96exports.MetaFile = MetaFile;
97// Container for info about a particular target file.
98//
99// This class is used for Target metadata.
100class TargetFile {
101    length;
102    path;
103    hashes;
104    unrecognizedFields;
105    constructor(opts) {
106        validateLength(opts.length);
107        this.length = opts.length;
108        this.path = opts.path;
109        this.hashes = opts.hashes;
110        this.unrecognizedFields = opts.unrecognizedFields || {};
111    }
112    get custom() {
113        const custom = this.unrecognizedFields['custom'];
114        if (!custom || Array.isArray(custom) || !(typeof custom === 'object')) {
115            return {};
116        }
117        return custom;
118    }
119    equals(other) {
120        if (!(other instanceof TargetFile)) {
121            return false;
122        }
123        return (this.length === other.length &&
124            this.path === other.path &&
125            util_1.default.isDeepStrictEqual(this.hashes, other.hashes) &&
126            util_1.default.isDeepStrictEqual(this.unrecognizedFields, other.unrecognizedFields));
127    }
128    async verify(stream) {
129        let observedLength = 0;
130        // Create a digest for each hash algorithm
131        const digests = Object.keys(this.hashes).reduce((acc, key) => {
132            try {
133                acc[key] = crypto_1.default.createHash(key);
134            }
135            catch (e) {
136                throw new error_1.LengthOrHashMismatchError(`Hash algorithm ${key} not supported`);
137            }
138            return acc;
139        }, {});
140        // Read stream chunk by chunk
141        for await (const chunk of stream) {
142            // Keep running tally of stream length
143            observedLength += chunk.length;
144            // Append chunk to each digest
145            Object.values(digests).forEach((digest) => {
146                digest.update(chunk);
147            });
148        }
149        // Verify length matches expected value
150        if (observedLength !== this.length) {
151            throw new error_1.LengthOrHashMismatchError(`Expected length ${this.length} but got ${observedLength}`);
152        }
153        // Verify each digest matches expected value
154        Object.entries(digests).forEach(([key, value]) => {
155            const expected = this.hashes[key];
156            const actual = value.digest('hex');
157            if (actual !== expected) {
158                throw new error_1.LengthOrHashMismatchError(`Expected hash ${expected} but got ${actual}`);
159            }
160        });
161    }
162    toJSON() {
163        return {
164            length: this.length,
165            hashes: this.hashes,
166            ...this.unrecognizedFields,
167        };
168    }
169    static fromJSON(path, data) {
170        const { length, hashes, ...rest } = data;
171        if (typeof length !== 'number') {
172            throw new TypeError('length must be a number');
173        }
174        if (!utils_1.guard.isStringRecord(hashes)) {
175            throw new TypeError('hashes must have string keys and values');
176        }
177        return new TargetFile({
178            length,
179            path,
180            hashes,
181            unrecognizedFields: rest,
182        });
183    }
184}
185exports.TargetFile = TargetFile;
186// Check that supplied length if valid
187function validateLength(length) {
188    if (length < 0) {
189        throw new error_1.ValueError('Length must be at least 0');
190    }
191}
192 
codekingpro/portable-devtools · Team Ai