@dcl/content-validator 1.0.0-20220104134007.commit-80072ed
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +29 -0
- package/dist/content-validator.api.json +1177 -0
- package/dist/index.d.ts +8 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +32 -0
- package/dist/index.js.map +1 -0
- package/dist/tsdoc-metadata.json +11 -0
- package/dist/types.d.ts +114 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +36 -0
- package/dist/types.js.map +1 -0
- package/dist/validations/access-checker/access.d.ts +7 -0
- package/dist/validations/access-checker/access.d.ts.map +1 -0
- package/dist/validations/access-checker/access.js +28 -0
- package/dist/validations/access-checker/access.js.map +1 -0
- package/dist/validations/access-checker/profiles.d.ts +7 -0
- package/dist/validations/access-checker/profiles.d.ts.map +1 -0
- package/dist/validations/access-checker/profiles.js +30 -0
- package/dist/validations/access-checker/profiles.js.map +1 -0
- package/dist/validations/access-checker/scenes.d.ts +7 -0
- package/dist/validations/access-checker/scenes.d.ts.map +1 -0
- package/dist/validations/access-checker/scenes.js +246 -0
- package/dist/validations/access-checker/scenes.js.map +1 -0
- package/dist/validations/access-checker/wearables.d.ts +20 -0
- package/dist/validations/access-checker/wearables.d.ts.map +1 -0
- package/dist/validations/access-checker/wearables.js +247 -0
- package/dist/validations/access-checker/wearables.js.map +1 -0
- package/dist/validations/content.d.ts +7 -0
- package/dist/validations/content.d.ts.map +1 -0
- package/dist/validations/content.js +48 -0
- package/dist/validations/content.js.map +1 -0
- package/dist/validations/decentraland-address.d.ts +6 -0
- package/dist/validations/decentraland-address.d.ts.map +1 -0
- package/dist/validations/decentraland-address.js +19 -0
- package/dist/validations/decentraland-address.js.map +1 -0
- package/dist/validations/entity-structure.d.ts +7 -0
- package/dist/validations/entity-structure.d.ts.map +1 -0
- package/dist/validations/entity-structure.js +21 -0
- package/dist/validations/entity-structure.js.map +1 -0
- package/dist/validations/index.d.ts +22 -0
- package/dist/validations/index.d.ts.map +1 -0
- package/dist/validations/index.js +76 -0
- package/dist/validations/index.js.map +1 -0
- package/dist/validations/ipfs-hashing.d.ts +7 -0
- package/dist/validations/ipfs-hashing.d.ts.map +1 -0
- package/dist/validations/ipfs-hashing.js +25 -0
- package/dist/validations/ipfs-hashing.js.map +1 -0
- package/dist/validations/metadata-schema.d.ts +6 -0
- package/dist/validations/metadata-schema.d.ts.map +1 -0
- package/dist/validations/metadata-schema.js +26 -0
- package/dist/validations/metadata-schema.js.map +1 -0
- package/dist/validations/must-have-failed-before.d.ts +6 -0
- package/dist/validations/must-have-failed-before.d.ts.map +1 -0
- package/dist/validations/must-have-failed-before.js +13 -0
- package/dist/validations/must-have-failed-before.js.map +1 -0
- package/dist/validations/no-newer.d.ts +6 -0
- package/dist/validations/no-newer.d.ts.map +1 -0
- package/dist/validations/no-newer.js +14 -0
- package/dist/validations/no-newer.js.map +1 -0
- package/dist/validations/no-redeploy.d.ts +6 -0
- package/dist/validations/no-redeploy.d.ts.map +1 -0
- package/dist/validations/no-redeploy.js +13 -0
- package/dist/validations/no-redeploy.js.map +1 -0
- package/dist/validations/rate-limit.d.ts +6 -0
- package/dist/validations/rate-limit.d.ts.map +1 -0
- package/dist/validations/rate-limit.js +13 -0
- package/dist/validations/rate-limit.js.map +1 -0
- package/dist/validations/recent.d.ts +7 -0
- package/dist/validations/recent.d.ts.map +1 -0
- package/dist/validations/recent.js +27 -0
- package/dist/validations/recent.js.map +1 -0
- package/dist/validations/signature.d.ts +7 -0
- package/dist/validations/signature.d.ts.map +1 -0
- package/dist/validations/signature.js +17 -0
- package/dist/validations/signature.js.map +1 -0
- package/dist/validations/size.d.ts +8 -0
- package/dist/validations/size.d.ts.map +1 -0
- package/dist/validations/size.js +39 -0
- package/dist/validations/size.js.map +1 -0
- package/dist/validations/wearable.d.ts +10 -0
- package/dist/validations/wearable.d.ts.map +1 -0
- package/dist/validations/wearable.js +76 -0
- package/dist/validations/wearable.js.map +1 -0
- package/package.json +47 -0
|
@@ -0,0 +1,247 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.wearables = void 0;
|
|
7
|
+
const urn_resolver_1 = require("@dcl/urn-resolver");
|
|
8
|
+
const dcl_catalyst_commons_1 = require("dcl-catalyst-commons");
|
|
9
|
+
const ms_1 = __importDefault(require("ms"));
|
|
10
|
+
const __1 = require("../..");
|
|
11
|
+
const types_1 = require("../../types");
|
|
12
|
+
const L1_NETWORKS = ['mainnet', 'ropsten', 'kovan', 'rinkeby', 'goerli'];
|
|
13
|
+
const L2_NETWORKS = ['matic', 'mumbai'];
|
|
14
|
+
// When we want to find a block for a specific timestamp, we define an access window. This means that
|
|
15
|
+
// we will place will try to find the closes block to the timestamp, but only if it's within the window
|
|
16
|
+
const ACCESS_WINDOW_IN_SECONDS = (0, ms_1.default)('15s') / 1000;
|
|
17
|
+
const alreadySeen = (resolvedPointers, parsed) => {
|
|
18
|
+
return resolvedPointers.some((alreadyResolved) => resolveSameUrn(alreadyResolved, parsed));
|
|
19
|
+
};
|
|
20
|
+
const resolveSameUrn = (alreadyParsed, parsed) => {
|
|
21
|
+
const alreadyParsedCopy = Object.assign({}, alreadyParsed);
|
|
22
|
+
const parsedCopy = Object.assign({}, parsed);
|
|
23
|
+
alreadyParsedCopy.uri = new URL('urn:same');
|
|
24
|
+
parsedCopy.uri = new URL('urn:same');
|
|
25
|
+
return JSON.stringify(alreadyParsedCopy) == JSON.stringify(parsedCopy);
|
|
26
|
+
};
|
|
27
|
+
const parseUrnNoFail = async (urn) => {
|
|
28
|
+
try {
|
|
29
|
+
const parsed = await (0, urn_resolver_1.parseUrn)(urn);
|
|
30
|
+
if (parsed?.type === 'blockchain-collection-v1-asset') {
|
|
31
|
+
return parsed;
|
|
32
|
+
}
|
|
33
|
+
if (parsed?.type === 'blockchain-collection-v2-asset') {
|
|
34
|
+
return parsed;
|
|
35
|
+
}
|
|
36
|
+
if (parsed?.type === 'off-chain') {
|
|
37
|
+
return parsed;
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
catch { }
|
|
41
|
+
return null;
|
|
42
|
+
};
|
|
43
|
+
const hasPermission = async (subgraphUrl, collection, itemId, block, entity, externalCalls) => {
|
|
44
|
+
try {
|
|
45
|
+
const { content, metadata } = entity;
|
|
46
|
+
const permissions = await getCollectionItems(subgraphUrl, collection, itemId, block, externalCalls);
|
|
47
|
+
const ethAddressLowercase = entity.ethAddress.toLowerCase();
|
|
48
|
+
if (!!permissions.contentHash) {
|
|
49
|
+
const deployedByCommittee = permissions.committee.includes(ethAddressLowercase);
|
|
50
|
+
const calculateHashes = () => {
|
|
51
|
+
// Compare both by key and hash
|
|
52
|
+
const compare = (a, b) => {
|
|
53
|
+
if (a.hash > b.hash)
|
|
54
|
+
return 1;
|
|
55
|
+
else if (a.hash < b.hash)
|
|
56
|
+
return -1;
|
|
57
|
+
else
|
|
58
|
+
return a.key > b.key ? 1 : -1;
|
|
59
|
+
};
|
|
60
|
+
const contentAsJson = (content ?? []).map(({ file, hash }) => ({ key: file, hash })).sort(compare);
|
|
61
|
+
const buffer = Buffer.from(JSON.stringify({ content: contentAsJson, metadata }));
|
|
62
|
+
return Promise.all([dcl_catalyst_commons_1.Hashing.calculateBufferHash(buffer), dcl_catalyst_commons_1.Hashing.calculateIPFSHash(buffer)]);
|
|
63
|
+
};
|
|
64
|
+
return deployedByCommittee && (await calculateHashes()).includes(permissions.contentHash);
|
|
65
|
+
}
|
|
66
|
+
else {
|
|
67
|
+
const addressHasAccess = (permissions.collectionCreator && permissions.collectionCreator === ethAddressLowercase) ||
|
|
68
|
+
(permissions.collectionManagers && permissions.collectionManagers.includes(ethAddressLowercase)) ||
|
|
69
|
+
(permissions.itemManagers && permissions.itemManagers.includes(ethAddressLowercase));
|
|
70
|
+
// Deployments to the content server are made after the collection is completed, so that the committee can then approve it.
|
|
71
|
+
// That's why isCompleted must be true, but isApproved must be false. After the committee approves the wearable, there can't be any more changes
|
|
72
|
+
const isCollectionValid = !permissions.isApproved && permissions.isCompleted;
|
|
73
|
+
return addressHasAccess && isCollectionValid;
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
catch (error) {
|
|
77
|
+
// this.LOGGER.error(`Error checking permission for (${collection}-${itemId}) at block ${block}`, error)
|
|
78
|
+
return false;
|
|
79
|
+
}
|
|
80
|
+
};
|
|
81
|
+
const getCollectionItems = async (subgraphUrl, collection, itemId, block, externalCalls) => {
|
|
82
|
+
const query = `
|
|
83
|
+
query getCollectionRoles($collection: String!, $itemId: String!, $block: Int!) {
|
|
84
|
+
collections(where:{ id: $collection }, block: { number: $block }) {
|
|
85
|
+
creator
|
|
86
|
+
managers
|
|
87
|
+
isApproved
|
|
88
|
+
isCompleted
|
|
89
|
+
items(where:{ id: $itemId }) {
|
|
90
|
+
managers
|
|
91
|
+
contentHash
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
accounts(where:{ isCommitteeMember: true }, block: { number: $block }) {
|
|
96
|
+
id
|
|
97
|
+
}
|
|
98
|
+
}`;
|
|
99
|
+
const result = await externalCalls.queryGraph(subgraphUrl, query, {
|
|
100
|
+
collection,
|
|
101
|
+
itemId: `${collection}-${itemId}`,
|
|
102
|
+
block,
|
|
103
|
+
});
|
|
104
|
+
const collectionResult = result.collections[0];
|
|
105
|
+
const itemResult = collectionResult?.items[0];
|
|
106
|
+
return {
|
|
107
|
+
collectionCreator: collectionResult?.creator,
|
|
108
|
+
collectionManagers: collectionResult?.managers,
|
|
109
|
+
isApproved: collectionResult?.isApproved,
|
|
110
|
+
isCompleted: collectionResult?.isCompleted,
|
|
111
|
+
itemManagers: itemResult?.managers,
|
|
112
|
+
contentHash: itemResult?.contentHash,
|
|
113
|
+
committee: result.accounts.map(({ id }) => id.toLowerCase()),
|
|
114
|
+
};
|
|
115
|
+
};
|
|
116
|
+
const getWindowFromTimestamp = (timestamp) => {
|
|
117
|
+
const windowMin = timestamp - Math.floor(ACCESS_WINDOW_IN_SECONDS / 2);
|
|
118
|
+
const windowMax = timestamp + Math.ceil(ACCESS_WINDOW_IN_SECONDS / 2);
|
|
119
|
+
return {
|
|
120
|
+
max: windowMax,
|
|
121
|
+
min: windowMin,
|
|
122
|
+
};
|
|
123
|
+
};
|
|
124
|
+
const findBlocksForTimestamp = async (blocksSubgraphUrl, timestamp, externalCalls) => {
|
|
125
|
+
const query = `
|
|
126
|
+
query getBlockForTimestamp($timestamp: Int!, $timestampMin: Int!, $timestampMax: Int!, $timestamp5Min: Int!, $timestamp5MinMax: Int!, $timestamp5MinMin: Int!) {
|
|
127
|
+
before: blocks(where: { timestamp_lte: $timestamp, timestamp_gte: $timestampMin }, first: 1, orderBy: timestamp, orderDirection: desc) {
|
|
128
|
+
number
|
|
129
|
+
}
|
|
130
|
+
after: blocks(where: { timestamp_gte: $timestamp, timestamp_lte: $timestampMax }, first: 1, orderBy: timestamp, orderDirection: asc) {
|
|
131
|
+
number
|
|
132
|
+
}
|
|
133
|
+
fiveMinBefore: blocks(where: { timestamp_lte: $timestamp5Min, timestamp_gte: $timestamp5MinMin, }, first: 1, orderBy: timestamp, orderDirection: desc) {
|
|
134
|
+
number
|
|
135
|
+
}
|
|
136
|
+
fiveMinAfter: blocks(where: { timestamp_gte: $timestamp5Min, timestamp_lte: $timestamp5MinMax }, first: 1, orderBy: timestamp, orderDirection: asc) {
|
|
137
|
+
number
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
`;
|
|
141
|
+
try {
|
|
142
|
+
const timestampSec = Math.ceil(timestamp / 1000);
|
|
143
|
+
const timestamp5MinAgo = timestampSec - 60 * 5;
|
|
144
|
+
const window = getWindowFromTimestamp(timestampSec);
|
|
145
|
+
const window5MinAgo = getWindowFromTimestamp(timestamp5MinAgo);
|
|
146
|
+
const result = await externalCalls.queryGraph(blocksSubgraphUrl, query, {
|
|
147
|
+
timestamp: timestampSec,
|
|
148
|
+
timestampMax: window.max,
|
|
149
|
+
timestampMin: window.min,
|
|
150
|
+
timestamp5Min: timestamp5MinAgo,
|
|
151
|
+
timestamp5MinMax: window5MinAgo.max,
|
|
152
|
+
timestamp5MinMin: window5MinAgo.min,
|
|
153
|
+
});
|
|
154
|
+
// To get the deployment's block number, we check the one immediately after the entity's timestamp. Since it could not exist, we default to the one immediately before.
|
|
155
|
+
const blockNumberAtDeployment = result.after[0]?.number ?? result.before[0]?.number;
|
|
156
|
+
const blockNumberFiveMinBeforeDeployment = result.fiveMinAfter[0]?.number ?? result.fiveMinBefore[0]?.number;
|
|
157
|
+
if (blockNumberAtDeployment === undefined && blockNumberFiveMinBeforeDeployment === undefined) {
|
|
158
|
+
throw new Error(`Failed to find blocks for the specific timestamp`);
|
|
159
|
+
}
|
|
160
|
+
return {
|
|
161
|
+
blockNumberAtDeployment: !!blockNumberAtDeployment ? parseInt(blockNumberAtDeployment) : undefined,
|
|
162
|
+
blockNumberFiveMinBeforeDeployment: !!blockNumberFiveMinBeforeDeployment
|
|
163
|
+
? parseInt(blockNumberFiveMinBeforeDeployment)
|
|
164
|
+
: undefined,
|
|
165
|
+
};
|
|
166
|
+
}
|
|
167
|
+
catch (error) {
|
|
168
|
+
// this.LOGGER.error(`Error fetching the block number for timestamp`, { timestamp, error: error.message })
|
|
169
|
+
throw error;
|
|
170
|
+
}
|
|
171
|
+
};
|
|
172
|
+
const checkCollectionAccess = async (blocksSubgraphUrl, collectionsSubgraphUrl, collection, itemId, entity, externalCalls) => {
|
|
173
|
+
const { timestamp } = entity;
|
|
174
|
+
try {
|
|
175
|
+
const { blockNumberAtDeployment, blockNumberFiveMinBeforeDeployment } = await findBlocksForTimestamp(blocksSubgraphUrl, timestamp, externalCalls);
|
|
176
|
+
// It could happen that the subgraph hasn't synced yet, so someone who just lost access still managed to make a deployment. The problem would be that when other catalysts perform
|
|
177
|
+
// the same check, the subgraph might have synced and the deployment is no longer valid. So, in order to prevent inconsistencies between catalysts, we will allow all deployments that
|
|
178
|
+
// have access now, or had access 5 minutes ago.
|
|
179
|
+
const hasPermissionOnBlock = async (blockNumber) => !!blockNumber &&
|
|
180
|
+
(await hasPermission(collectionsSubgraphUrl, collection, itemId, blockNumber, entity, externalCalls));
|
|
181
|
+
return ((await hasPermissionOnBlock(blockNumberAtDeployment)) ||
|
|
182
|
+
(await hasPermissionOnBlock(blockNumberFiveMinBeforeDeployment)));
|
|
183
|
+
}
|
|
184
|
+
catch (error) {
|
|
185
|
+
// this.LOGGER.error(
|
|
186
|
+
// `Error checking wearable access (${collection}, ${itemId}, ${accessParams.ethAddress}, ${timestamp}, ${blocksSubgraphUrl}).`,
|
|
187
|
+
// error
|
|
188
|
+
// )
|
|
189
|
+
return false;
|
|
190
|
+
}
|
|
191
|
+
};
|
|
192
|
+
/**
|
|
193
|
+
* Given the pointers (URNs), determine which layer should be used to check the access.
|
|
194
|
+
* Checks if the ethereum address has access to the collection.
|
|
195
|
+
* @public
|
|
196
|
+
*/
|
|
197
|
+
exports.wearables = {
|
|
198
|
+
validate: async ({ deployment, externalCalls }) => {
|
|
199
|
+
const { pointers } = deployment.entity;
|
|
200
|
+
const ethAddress = externalCalls.ownerAddress(deployment.auditInfo);
|
|
201
|
+
const resolvedPointers = [];
|
|
202
|
+
// deduplicate pointer resolution
|
|
203
|
+
for (const pointer of pointers) {
|
|
204
|
+
const parsed = await parseUrnNoFail(pointer);
|
|
205
|
+
if (!parsed)
|
|
206
|
+
return (0, __1.validationFailed)(`Wearable pointers should be a urn, for example (urn:decentraland:{protocol}:collections-v2:{contract(0x[a-fA-F0-9]+)}:{name}). Invalid pointer: (${pointer})`);
|
|
207
|
+
if (!alreadySeen(resolvedPointers, parsed))
|
|
208
|
+
resolvedPointers.push(parsed);
|
|
209
|
+
}
|
|
210
|
+
if (resolvedPointers.length > 1)
|
|
211
|
+
return (0, __1.validationFailed)(`Only one pointer is allowed when you create a Wearable. Received: ${pointers}`);
|
|
212
|
+
const parsed = resolvedPointers[0];
|
|
213
|
+
if (!['off-chain', 'blockchain-collection-v1-asset', 'blockchain-collection-v2-asset'].includes(parsed.type))
|
|
214
|
+
return (0, __1.validationFailed)(`Could not resolve the contractAddress of the urn ${parsed}`);
|
|
215
|
+
if (parsed.type === 'off-chain') {
|
|
216
|
+
// Validate Off Chain Asset
|
|
217
|
+
if (!externalCalls.isAddressOwnedByDecentraland(ethAddress))
|
|
218
|
+
return (0, __1.validationFailed)(`The provided Eth Address '${ethAddress}' does not have access to the following wearable: '${parsed.uri}'`);
|
|
219
|
+
}
|
|
220
|
+
else if (parsed?.type === 'blockchain-collection-v1-asset' || parsed?.type === 'blockchain-collection-v2-asset') {
|
|
221
|
+
// L1 or L2 so contractAddress is present
|
|
222
|
+
const collection = parsed.contractAddress;
|
|
223
|
+
const network = parsed.network;
|
|
224
|
+
const isL1 = L1_NETWORKS.includes(network);
|
|
225
|
+
const isL2 = L2_NETWORKS.includes(network);
|
|
226
|
+
if (!isL1 && !isL2)
|
|
227
|
+
return (0, __1.validationFailed)(`Found an unknown network on the urn '${network}'`);
|
|
228
|
+
const blocksSubgraphUrl = isL1 ? externalCalls.subgraphs.L1.blocks : externalCalls.subgraphs.L2.blocks;
|
|
229
|
+
const collectionsSubgraphUrl = isL1
|
|
230
|
+
? externalCalls.subgraphs.L1.collections
|
|
231
|
+
: externalCalls.subgraphs.L2.collections;
|
|
232
|
+
const hasAccess = await checkCollectionAccess(blocksSubgraphUrl, collectionsSubgraphUrl, collection, parsed.id, { ...deployment.entity, ethAddress }, externalCalls);
|
|
233
|
+
if (!hasAccess) {
|
|
234
|
+
if (isL2)
|
|
235
|
+
return (0, __1.validationFailed)(`The provided Eth Address does not have access to the following wearable: (${parsed.contractAddress}, ${parsed.id})`);
|
|
236
|
+
// Some L1 collections are deployed by Decentraland Address
|
|
237
|
+
// Maybe this is not necessary as we already know that it's a 'blockchain-collection-v1-asset'
|
|
238
|
+
const isAllowlistedCollection = parsed.uri.toString().startsWith('urn:decentraland:ethereum:collections-v1');
|
|
239
|
+
if (!externalCalls.isAddressOwnedByDecentraland(ethAddress) || !isAllowlistedCollection) {
|
|
240
|
+
return (0, __1.validationFailed)(`The provided Eth Address '${ethAddress}' does not have access to the following wearable: '${parsed.uri}'`);
|
|
241
|
+
}
|
|
242
|
+
}
|
|
243
|
+
}
|
|
244
|
+
return types_1.OK;
|
|
245
|
+
},
|
|
246
|
+
};
|
|
247
|
+
//# sourceMappingURL=wearables.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"wearables.js","sourceRoot":"","sources":["../../../src/validations/access-checker/wearables.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"content.d.ts","sourceRoot":"","sources":["../../src/validations/content.ts"],"names":[],"mappings":"AAGA,OAAO,EAAc,UAAU,EAAE,MAAM,UAAU,CAAA;AAUjD;;;GAGG;AACH,eAAO,MAAM,OAAO,EAAE,UAqCrB,CAAA"}
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.content = void 0;
|
|
4
|
+
const dcl_catalyst_commons_1 = require("dcl-catalyst-commons");
|
|
5
|
+
const _1 = require(".");
|
|
6
|
+
const types_1 = require("../types");
|
|
7
|
+
const correspondsToASnapshot = (fileName, hash, metadata) => {
|
|
8
|
+
const fileNameWithoutExtension = fileName.replace(/.[^/.]+$/, '');
|
|
9
|
+
return metadata.avatars.some((avatar) => Object.entries(avatar.avatar.snapshots).some((key) => key[0] === fileNameWithoutExtension && key[1] === hash));
|
|
10
|
+
};
|
|
11
|
+
/**
|
|
12
|
+
* Validate that uploaded and reported hashes are corrects and files corresponds to snapshots
|
|
13
|
+
* @public
|
|
14
|
+
*/
|
|
15
|
+
exports.content = {
|
|
16
|
+
validate: async ({ deployment, externalCalls }) => {
|
|
17
|
+
const { entity, files } = deployment;
|
|
18
|
+
const errors = [];
|
|
19
|
+
if (entity.content) {
|
|
20
|
+
const alreadyStoredHashes = await externalCalls.isContentStoredAlready(Array.from(files.keys()));
|
|
21
|
+
for (const { hash } of entity.content) {
|
|
22
|
+
// Validate that all hashes in entity were uploaded, or were already stored on the service
|
|
23
|
+
if (!(files.has(hash) || alreadyStoredHashes.get(hash))) {
|
|
24
|
+
errors.push(`This hash is referenced in the entity but was not uploaded or previously available: ${hash}`);
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
// Validate that all hashes that belong to uploaded files are actually reported on the entity
|
|
29
|
+
const entityHashes = new Set(entity.content?.map(({ hash }) => hash) ?? []);
|
|
30
|
+
for (const [hash] of files) {
|
|
31
|
+
if (!entityHashes.has(hash) && hash !== entity.id) {
|
|
32
|
+
errors.push(`This hash was uploaded but is not referenced in the entity: ${hash}`);
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
if (entity.timestamp > _1.ADR_X_TIMESTAMP) {
|
|
36
|
+
for (const { file, hash } of entity.content ?? []) {
|
|
37
|
+
// Validate all content files correspond to at least one avatar snapshot
|
|
38
|
+
if (entity.type === dcl_catalyst_commons_1.EntityType.PROFILE) {
|
|
39
|
+
if (!correspondsToASnapshot(file, hash, entity.metadata)) {
|
|
40
|
+
errors.push(`This file is not expected: '${file}' or its hash is invalid: '${hash}'. Please, include only valid snapshot files.`);
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
return (0, types_1.fromErrors)(...errors);
|
|
46
|
+
},
|
|
47
|
+
};
|
|
48
|
+
//# sourceMappingURL=content.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"content.js","sourceRoot":"","sources":["../../src/validations/content.ts"],"names":[],"mappings":";;;AACA,+DAAiD;AACjD,wBAAmC;AACnC,oCAAiD;AAEjD,MAAM,sBAAsB,GAAG,CAAC,QAAgB,EAAE,IAAY,EAAE,QAAiB,EAAE,EAAE;IACnF,MAAM,wBAAwB,GAAG,QAAQ,CAAC,OAAO,CAAC,UAAU,EAAE,EAAE,CAAC,CAAA;IAEjE,OAAO,QAAQ,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,MAAc,EAAE,EAAE,CAC9C,MAAM,CAAC,OAAO,CAAC,MAAM,CAAC,MAAM,CAAC,SAAS,CAAC,CAAC,IAAI,CAAC,CAAC,GAAG,EAAE,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC,KAAK,wBAAwB,IAAI,GAAG,CAAC,CAAC,CAAC,KAAK,IAAI,CAAC,CAC9G,CAAA;AACH,CAAC,CAAA;AAED;;;GAGG;AACU,QAAA,OAAO,GAAe;IACjC,QAAQ,EAAE,KAAK,EAAE,EAAE,UAAU,EAAE,aAAa,EAAE,EAAE,EAAE;QAChD,MAAM,EAAE,MAAM,EAAE,KAAK,EAAE,GAAG,UAAU,CAAA;QACpC,MAAM,MAAM,GAAa,EAAE,CAAA;QAC3B,IAAI,MAAM,CAAC,OAAO,EAAE;YAClB,MAAM,mBAAmB,GAAG,MAAM,aAAa,CAAC,sBAAsB,CAAC,KAAK,CAAC,IAAI,CAAC,KAAK,CAAC,IAAI,EAAE,CAAC,CAAC,CAAA;YAEhG,KAAK,MAAM,EAAE,IAAI,EAAE,IAAI,MAAM,CAAC,OAAO,EAAE;gBACrC,0FAA0F;gBAC1F,IAAI,CAAC,CAAC,KAAK,CAAC,GAAG,CAAC,IAAI,CAAC,IAAI,mBAAmB,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC,EAAE;oBACvD,MAAM,CAAC,IAAI,CAAC,uFAAuF,IAAI,EAAE,CAAC,CAAA;iBAC3G;aACF;SACF;QAED,6FAA6F;QAC7F,MAAM,YAAY,GAAG,IAAI,GAAG,CAAC,MAAM,CAAC,OAAO,EAAE,GAAG,CAAC,CAAC,EAAE,IAAI,EAAE,EAAE,EAAE,CAAC,IAAI,CAAC,IAAI,EAAE,CAAC,CAAA;QAC3E,KAAK,MAAM,CAAC,IAAI,CAAC,IAAI,KAAK,EAAE;YAC1B,IAAI,CAAC,YAAY,CAAC,GAAG,CAAC,IAAI,CAAC,IAAI,IAAI,KAAK,MAAM,CAAC,EAAE,EAAE;gBACjD,MAAM,CAAC,IAAI,CAAC,+DAA+D,IAAI,EAAE,CAAC,CAAA;aACnF;SACF;QAED,IAAI,MAAM,CAAC,SAAS,GAAG,kBAAe,EAAE;YACtC,KAAK,MAAM,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,MAAM,CAAC,OAAO,IAAI,EAAE,EAAE;gBACjD,wEAAwE;gBACxE,IAAI,MAAM,CAAC,IAAI,KAAK,iCAAU,CAAC,OAAO,EAAE;oBACtC,IAAI,CAAC,sBAAsB,CAAC,IAAI,EAAE,IAAI,EAAE,MAAM,CAAC,QAAQ,CAAC,EAAE;wBACxD,MAAM,CAAC,IAAI,CACT,+BAA+B,IAAI,8BAA8B,IAAI,+CAA+C,CACrH,CAAA;qBACF;iBACF;aACF;SACF;QACD,OAAO,IAAA,kBAAU,EAAC,GAAG,MAAM,CAAC,CAAA;IAC9B,CAAC;CACF,CAAA"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"decentraland-address.d.ts","sourceRoot":"","sources":["../../src/validations/decentraland-address.ts"],"names":[],"mappings":"AAEA;;;GAGG;AACH,eAAO,MAAM,mBAAmB,+BAS9B,CAAA"}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.decentralandAddress = void 0;
|
|
4
|
+
const types_1 = require("../types");
|
|
5
|
+
/**
|
|
6
|
+
* Validate that the address used was owned by Decentraland
|
|
7
|
+
* @public
|
|
8
|
+
*/
|
|
9
|
+
exports.decentralandAddress = (0, types_1.conditionalValidation)({
|
|
10
|
+
predicate: ({ deployment, externalCalls }) => {
|
|
11
|
+
const address = externalCalls.ownerAddress(deployment.auditInfo);
|
|
12
|
+
return externalCalls.isAddressOwnedByDecentraland(address);
|
|
13
|
+
},
|
|
14
|
+
message: ({ deployment, externalCalls }) => {
|
|
15
|
+
const address = externalCalls.ownerAddress(deployment.auditInfo);
|
|
16
|
+
return `Expected an address owned by decentraland. Instead, we found ${address}`;
|
|
17
|
+
},
|
|
18
|
+
});
|
|
19
|
+
//# sourceMappingURL=decentraland-address.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"decentraland-address.js","sourceRoot":"","sources":["../../src/validations/decentraland-address.ts"],"names":[],"mappings":";;;AAAA,oCAAgD;AAEhD;;;GAGG;AACU,QAAA,mBAAmB,GAAG,IAAA,6BAAqB,EAAC;IACvD,SAAS,EAAE,CAAC,EAAE,UAAU,EAAE,aAAa,EAAE,EAAE,EAAE;QAC3C,MAAM,OAAO,GAAG,aAAa,CAAC,YAAY,CAAC,UAAU,CAAC,SAAS,CAAC,CAAA;QAChE,OAAO,aAAa,CAAC,4BAA4B,CAAC,OAAO,CAAC,CAAA;IAC5D,CAAC;IACD,OAAO,EAAE,CAAC,EAAE,UAAU,EAAE,aAAa,EAAE,EAAE,EAAE;QACzC,MAAM,OAAO,GAAG,aAAa,CAAC,YAAY,CAAC,UAAU,CAAC,SAAS,CAAC,CAAA;QAChE,OAAO,gEAAgE,OAAO,EAAE,CAAA;IAClF,CAAC;CACF,CAAC,CAAA"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"entity-structure.d.ts","sourceRoot":"","sources":["../../src/validations/entity-structure.ts"],"names":[],"mappings":"AAAA,OAAO,EAAM,UAAU,EAAoB,MAAM,UAAU,CAAA;AAE3D;;;GAGG;AACH,eAAO,MAAM,eAAe,EAAE,UAU7B,CAAA"}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.entityStructure = void 0;
|
|
4
|
+
const types_1 = require("../types");
|
|
5
|
+
/**
|
|
6
|
+
* Validate that entity is actually ok
|
|
7
|
+
* @public
|
|
8
|
+
*/
|
|
9
|
+
exports.entityStructure = {
|
|
10
|
+
validate: async ({ deployment }) => {
|
|
11
|
+
const { entity } = deployment;
|
|
12
|
+
if (new Set(entity.pointers).size != entity.pointers.length) {
|
|
13
|
+
return (0, types_1.validationFailed)('There are repeated pointers in your request.');
|
|
14
|
+
}
|
|
15
|
+
else if (!entity.pointers || entity.pointers.length <= 0) {
|
|
16
|
+
return (0, types_1.validationFailed)('The entity needs to be pointed by one or more pointers.');
|
|
17
|
+
}
|
|
18
|
+
return types_1.OK;
|
|
19
|
+
},
|
|
20
|
+
};
|
|
21
|
+
//# sourceMappingURL=entity-structure.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"entity-structure.js","sourceRoot":"","sources":["../../src/validations/entity-structure.ts"],"names":[],"mappings":";;;AAAA,oCAA2D;AAE3D;;;GAGG;AACU,QAAA,eAAe,GAAe;IACzC,QAAQ,EAAE,KAAK,EAAE,EAAE,UAAU,EAAE,EAAE,EAAE;QACjC,MAAM,EAAE,MAAM,EAAE,GAAG,UAAU,CAAA;QAC7B,IAAI,IAAI,GAAG,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC,IAAI,IAAI,MAAM,CAAC,QAAQ,CAAC,MAAM,EAAE;YAC3D,OAAO,IAAA,wBAAgB,EAAC,8CAA8C,CAAC,CAAA;SACxE;aAAM,IAAI,CAAC,MAAM,CAAC,QAAQ,IAAI,MAAM,CAAC,QAAQ,CAAC,MAAM,IAAI,CAAC,EAAE;YAC1D,OAAO,IAAA,wBAAgB,EAAC,yDAAyD,CAAC,CAAA;SACnF;QACD,OAAO,UAAE,CAAA;IACX,CAAC;CACF,CAAA"}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import { DeploymentToValidate, ExternalCalls, Validation, ValidationArgs, ValidationResponse } from '../types';
|
|
2
|
+
/**
|
|
3
|
+
* @public
|
|
4
|
+
*/
|
|
5
|
+
export declare const validateInRow: (validationArgs: ValidationArgs, ...validations: Validation[]) => Promise<ValidationResponse>;
|
|
6
|
+
/**
|
|
7
|
+
* @public
|
|
8
|
+
*/
|
|
9
|
+
export declare const ADR_X_TIMESTAMP = 1648954800000;
|
|
10
|
+
/**
|
|
11
|
+
* @public
|
|
12
|
+
*/
|
|
13
|
+
export declare const calculateDeploymentSize: (deployment: DeploymentToValidate, externalCalls: ExternalCalls) => Promise<number | string>;
|
|
14
|
+
/**
|
|
15
|
+
* @public
|
|
16
|
+
*/
|
|
17
|
+
export declare const statefulValidations: Validation[];
|
|
18
|
+
/**
|
|
19
|
+
* @public
|
|
20
|
+
*/
|
|
21
|
+
export declare const statelessValidations: Validation[];
|
|
22
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/validations/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,oBAAoB,EAAE,aAAa,EAAM,UAAU,EAAE,cAAc,EAAE,kBAAkB,EAAE,MAAM,UAAU,CAAA;AAgBlH;;GAEG;AACH,eAAO,MAAM,aAAa,mBACR,cAAc,kBACd,UAAU,EAAE,KAC3B,QAAQ,kBAAkB,CAM5B,CAAA;AAGD;;GAEG;AACH,eAAO,MAAM,eAAe,gBAAgB,CAAA;AAE5C;;GAEG;AACH,eAAO,MAAM,uBAAuB,eACtB,oBAAoB,iBACjB,aAAa,KAC3B,QAAQ,MAAM,GAAG,MAAM,CAazB,CAAA;AAED;;GAEG;AACH,eAAO,MAAM,mBAAmB,cAY/B,CAAA;AACD;;GAEG;AACH,eAAO,MAAM,oBAAoB,cAA2C,CAAA"}
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.statelessValidations = exports.statefulValidations = exports.calculateDeploymentSize = exports.ADR_X_TIMESTAMP = exports.validateInRow = void 0;
|
|
4
|
+
const types_1 = require("../types");
|
|
5
|
+
const access_1 = require("./access-checker/access");
|
|
6
|
+
const content_1 = require("./content");
|
|
7
|
+
const decentraland_address_1 = require("./decentraland-address");
|
|
8
|
+
const entity_structure_1 = require("./entity-structure");
|
|
9
|
+
const ipfs_hashing_1 = require("./ipfs-hashing");
|
|
10
|
+
const metadata_schema_1 = require("./metadata-schema");
|
|
11
|
+
const must_have_failed_before_1 = require("./must-have-failed-before");
|
|
12
|
+
const no_newer_1 = require("./no-newer");
|
|
13
|
+
const no_redeploy_1 = require("./no-redeploy");
|
|
14
|
+
const rate_limit_1 = require("./rate-limit");
|
|
15
|
+
const recent_1 = require("./recent");
|
|
16
|
+
const signature_1 = require("./signature");
|
|
17
|
+
const size_1 = require("./size");
|
|
18
|
+
const wearable_1 = require("./wearable");
|
|
19
|
+
/**
|
|
20
|
+
* @public
|
|
21
|
+
*/
|
|
22
|
+
const validateInRow = async (validationArgs, ...validations) => {
|
|
23
|
+
for (const validation of validations) {
|
|
24
|
+
const response = await validation.validate(validationArgs);
|
|
25
|
+
if (!response.ok)
|
|
26
|
+
return response;
|
|
27
|
+
}
|
|
28
|
+
return types_1.OK;
|
|
29
|
+
};
|
|
30
|
+
exports.validateInRow = validateInRow;
|
|
31
|
+
// todo: review/define date for entities v4 (for the time being, it is set for test purposes)
|
|
32
|
+
/**
|
|
33
|
+
* @public
|
|
34
|
+
*/
|
|
35
|
+
exports.ADR_X_TIMESTAMP = 1648954800000;
|
|
36
|
+
/**
|
|
37
|
+
* @public
|
|
38
|
+
*/
|
|
39
|
+
const calculateDeploymentSize = async (deployment, externalCalls) => {
|
|
40
|
+
let totalSize = 0;
|
|
41
|
+
for (const hash of new Set(deployment.entity.content?.map((item) => item.hash) ?? [])) {
|
|
42
|
+
const uploadedFile = deployment.files.get(hash);
|
|
43
|
+
if (uploadedFile) {
|
|
44
|
+
totalSize += uploadedFile.byteLength;
|
|
45
|
+
}
|
|
46
|
+
else {
|
|
47
|
+
const contentSize = await externalCalls.fetchContentFileSize(hash);
|
|
48
|
+
if (!contentSize)
|
|
49
|
+
return `Couldn't fetch content file with hash: ${hash}`;
|
|
50
|
+
totalSize += contentSize;
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
return totalSize;
|
|
54
|
+
};
|
|
55
|
+
exports.calculateDeploymentSize = calculateDeploymentSize;
|
|
56
|
+
/**
|
|
57
|
+
* @public
|
|
58
|
+
*/
|
|
59
|
+
exports.statefulValidations = [
|
|
60
|
+
no_redeploy_1.noRedeploy,
|
|
61
|
+
signature_1.signature,
|
|
62
|
+
recent_1.recent,
|
|
63
|
+
no_newer_1.noNewer,
|
|
64
|
+
access_1.access,
|
|
65
|
+
size_1.size,
|
|
66
|
+
must_have_failed_before_1.mustHaveFailedBefore,
|
|
67
|
+
wearable_1.wearable,
|
|
68
|
+
content_1.content,
|
|
69
|
+
decentraland_address_1.decentralandAddress,
|
|
70
|
+
rate_limit_1.rateLimit,
|
|
71
|
+
];
|
|
72
|
+
/**
|
|
73
|
+
* @public
|
|
74
|
+
*/
|
|
75
|
+
exports.statelessValidations = [entity_structure_1.entityStructure, ipfs_hashing_1.ipfsHashing, metadata_schema_1.metadata];
|
|
76
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/validations/index.ts"],"names":[],"mappings":";;;AAAA,oCAAkH;AAClH,oDAAgD;AAChD,uCAAmC;AACnC,iEAA4D;AAC5D,yDAAoD;AACpD,iDAA4C;AAC5C,uDAA4C;AAC5C,uEAAgE;AAChE,yCAAoC;AACpC,+CAA0C;AAC1C,6CAAwC;AACxC,qCAAiC;AACjC,2CAAuC;AACvC,iCAA6B;AAC7B,yCAAqC;AAErC;;GAEG;AACI,MAAM,aAAa,GAAG,KAAK,EAChC,cAA8B,EAC9B,GAAG,WAAyB,EACC,EAAE;IAC/B,KAAK,MAAM,UAAU,IAAI,WAAW,EAAE;QACpC,MAAM,QAAQ,GAAG,MAAM,UAAU,CAAC,QAAQ,CAAC,cAAc,CAAC,CAAA;QAC1D,IAAI,CAAC,QAAQ,CAAC,EAAE;YAAE,OAAO,QAAQ,CAAA;KAClC;IACD,OAAO,UAAE,CAAA;AACX,CAAC,CAAA;AATY,QAAA,aAAa,iBASzB;AAED,6FAA6F;AAC7F;;GAEG;AACU,QAAA,eAAe,GAAG,aAAa,CAAA;AAE5C;;GAEG;AACI,MAAM,uBAAuB,GAAG,KAAK,EAC1C,UAAgC,EAChC,aAA4B,EACF,EAAE;IAC5B,IAAI,SAAS,GAAG,CAAC,CAAA;IACjB,KAAK,MAAM,IAAI,IAAI,IAAI,GAAG,CAAC,UAAU,CAAC,MAAM,CAAC,OAAO,EAAE,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,EAAE,CAAC,EAAE;QACrF,MAAM,YAAY,GAAG,UAAU,CAAC,KAAK,CAAC,GAAG,CAAC,IAAI,CAAC,CAAA;QAC/C,IAAI,YAAY,EAAE;YAChB,SAAS,IAAI,YAAY,CAAC,UAAU,CAAA;SACrC;aAAM;YACL,MAAM,WAAW,GAAG,MAAM,aAAa,CAAC,oBAAoB,CAAC,IAAI,CAAC,CAAA;YAClE,IAAI,CAAC,WAAW;gBAAE,OAAO,0CAA0C,IAAI,EAAE,CAAA;YACzE,SAAS,IAAI,WAAW,CAAA;SACzB;KACF;IACD,OAAO,SAAS,CAAA;AAClB,CAAC,CAAA;AAhBY,QAAA,uBAAuB,2BAgBnC;AAED;;GAEG;AACU,QAAA,mBAAmB,GAAG;IACjC,wBAAU;IACV,qBAAS;IACT,eAAM;IACN,kBAAO;IACP,eAAM;IACN,WAAI;IACJ,8CAAoB;IACpB,mBAAQ;IACR,iBAAO;IACP,0CAAmB;IACnB,sBAAS;CACV,CAAA;AACD;;GAEG;AACU,QAAA,oBAAoB,GAAG,CAAC,kCAAe,EAAE,0BAAW,EAAE,0BAAQ,CAAC,CAAA"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ipfs-hashing.d.ts","sourceRoot":"","sources":["../../src/validations/ipfs-hashing.ts"],"names":[],"mappings":"AAGA,OAAO,EAAc,UAAU,EAAE,MAAM,UAAU,CAAA;AAEjD;;;GAGG;AACH,eAAO,MAAM,WAAW,EAAE,UAezB,CAAA"}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.ipfsHashing = void 0;
|
|
4
|
+
const schemas_1 = require("@dcl/schemas");
|
|
5
|
+
const _1 = require(".");
|
|
6
|
+
const __1 = require("..");
|
|
7
|
+
const types_1 = require("../types");
|
|
8
|
+
/**
|
|
9
|
+
* Validate that all hashes used by the entity were actually IPFS hashes
|
|
10
|
+
* @public
|
|
11
|
+
*/
|
|
12
|
+
exports.ipfsHashing = {
|
|
13
|
+
validate: ({ deployment }) => {
|
|
14
|
+
const { entity } = deployment;
|
|
15
|
+
if (entity.timestamp < _1.ADR_X_TIMESTAMP)
|
|
16
|
+
return __1.OK;
|
|
17
|
+
const hashesInContent = entity.content?.map(({ hash }) => hash) ?? [];
|
|
18
|
+
const allHashes = [entity.id, ...hashesInContent];
|
|
19
|
+
const errors = allHashes
|
|
20
|
+
.filter((hash) => !schemas_1.IPFSv2.validate(hash))
|
|
21
|
+
.map((hash) => `This hash '${hash}' is not valid. It should be IPFS v2 format.`);
|
|
22
|
+
return (0, types_1.fromErrors)(...errors);
|
|
23
|
+
},
|
|
24
|
+
};
|
|
25
|
+
//# sourceMappingURL=ipfs-hashing.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ipfs-hashing.js","sourceRoot":"","sources":["../../src/validations/ipfs-hashing.ts"],"names":[],"mappings":";;;AAAA,0CAAqC;AACrC,wBAAmC;AACnC,0BAAuB;AACvB,oCAAiD;AAEjD;;;GAGG;AACU,QAAA,WAAW,GAAe;IACrC,QAAQ,EAAE,CAAC,EAAE,UAAU,EAAE,EAAE,EAAE;QAC3B,MAAM,EAAE,MAAM,EAAE,GAAG,UAAU,CAAA;QAE7B,IAAI,MAAM,CAAC,SAAS,GAAG,kBAAe;YAAE,OAAO,MAAE,CAAA;QAEjD,MAAM,eAAe,GAAG,MAAM,CAAC,OAAO,EAAE,GAAG,CAAC,CAAC,EAAE,IAAI,EAAE,EAAE,EAAE,CAAC,IAAI,CAAC,IAAI,EAAE,CAAA;QACrE,MAAM,SAAS,GAAG,CAAC,MAAM,CAAC,EAAE,EAAE,GAAG,eAAe,CAAC,CAAA;QAEjD,MAAM,MAAM,GAAG,SAAS;aACrB,MAAM,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,CAAC,gBAAM,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC;aACxC,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,cAAc,IAAI,8CAA8C,CAAC,CAAA;QAElF,OAAO,IAAA,kBAAU,EAAC,GAAG,MAAM,CAAC,CAAA;IAC9B,CAAC;CACF,CAAA"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"metadata-schema.d.ts","sourceRoot":"","sources":["../../src/validations/metadata-schema.ts"],"names":[],"mappings":"AAKA;;;GAGG;AACH,eAAO,MAAM,QAAQ,+BAYnB,CAAA"}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.metadata = void 0;
|
|
4
|
+
const schemas_1 = require("@dcl/schemas");
|
|
5
|
+
const dcl_catalyst_commons_1 = require("dcl-catalyst-commons");
|
|
6
|
+
const _1 = require(".");
|
|
7
|
+
const types_1 = require("../types");
|
|
8
|
+
/**
|
|
9
|
+
* Validate entities metadata against its corresponding schema
|
|
10
|
+
* @public
|
|
11
|
+
*/
|
|
12
|
+
exports.metadata = (0, types_1.conditionalValidation)({
|
|
13
|
+
predicate: ({ deployment }) => {
|
|
14
|
+
if (deployment.entity.timestamp <= _1.ADR_X_TIMESTAMP)
|
|
15
|
+
return true;
|
|
16
|
+
// todo: move this map to catalyst-commons
|
|
17
|
+
const validate = {
|
|
18
|
+
[dcl_catalyst_commons_1.EntityType.PROFILE]: schemas_1.Profile.validate,
|
|
19
|
+
[dcl_catalyst_commons_1.EntityType.SCENE]: schemas_1.Scene.validate,
|
|
20
|
+
[dcl_catalyst_commons_1.EntityType.WEARABLE]: schemas_1.Wearable.validate,
|
|
21
|
+
};
|
|
22
|
+
return validate[deployment.entity.type](deployment.entity.metadata);
|
|
23
|
+
},
|
|
24
|
+
message: ({ deployment }) => `The metadata for this entity type (${deployment.entity.type}) is not valid.`,
|
|
25
|
+
});
|
|
26
|
+
//# sourceMappingURL=metadata-schema.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"metadata-schema.js","sourceRoot":"","sources":["../../src/validations/metadata-schema.ts"],"names":[],"mappings":";;;AAAA,0CAAuD;AACvD,+DAAiD;AACjD,wBAAmC;AACnC,oCAAgD;AAEhD;;;GAGG;AACU,QAAA,QAAQ,GAAG,IAAA,6BAAqB,EAAC;IAC5C,SAAS,EAAE,CAAC,EAAE,UAAU,EAAE,EAAE,EAAE;QAC5B,IAAI,UAAU,CAAC,MAAM,CAAC,SAAS,IAAI,kBAAe;YAAE,OAAO,IAAI,CAAA;QAC/D,0CAA0C;QAC1C,MAAM,QAAQ,GAAG;YACf,CAAC,iCAAU,CAAC,OAAO,CAAC,EAAE,iBAAO,CAAC,QAAQ;YACtC,CAAC,iCAAU,CAAC,KAAK,CAAC,EAAE,eAAK,CAAC,QAAQ;YAClC,CAAC,iCAAU,CAAC,QAAQ,CAAC,EAAE,kBAAQ,CAAC,QAAQ;SACzC,CAAA;QACD,OAAO,QAAQ,CAAC,UAAU,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,UAAU,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAA;IACrE,CAAC;IACD,OAAO,EAAE,CAAC,EAAE,UAAU,EAAE,EAAE,EAAE,CAAC,sCAAsC,UAAU,CAAC,MAAM,CAAC,IAAI,iBAAiB;CAC3G,CAAC,CAAA"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"must-have-failed-before.d.ts","sourceRoot":"","sources":["../../src/validations/must-have-failed-before.ts"],"names":[],"mappings":"AAEA;;;GAGG;AACH,eAAO,MAAM,oBAAoB,+BAI/B,CAAA"}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.mustHaveFailedBefore = void 0;
|
|
4
|
+
const types_1 = require("../types");
|
|
5
|
+
/**
|
|
6
|
+
* Make sure that the deployment actually failed, and that it can be re-deployed
|
|
7
|
+
* @public
|
|
8
|
+
*/
|
|
9
|
+
exports.mustHaveFailedBefore = (0, types_1.conditionalValidation)({
|
|
10
|
+
predicate: async ({ deployment, externalCalls }) => await externalCalls.isFailedDeployment(deployment.entity.type, deployment.entity.id),
|
|
11
|
+
message: () => "This entity was already marked as failed. You can't fix it",
|
|
12
|
+
});
|
|
13
|
+
//# sourceMappingURL=must-have-failed-before.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"must-have-failed-before.js","sourceRoot":"","sources":["../../src/validations/must-have-failed-before.ts"],"names":[],"mappings":";;;AAAA,oCAAgD;AAEhD;;;GAGG;AACU,QAAA,oBAAoB,GAAG,IAAA,6BAAqB,EAAC;IACxD,SAAS,EAAE,KAAK,EAAE,EAAE,UAAU,EAAE,aAAa,EAAE,EAAE,EAAE,CACjD,MAAM,aAAa,CAAC,kBAAkB,CAAC,UAAU,CAAC,MAAM,CAAC,IAAI,EAAE,UAAU,CAAC,MAAM,CAAC,EAAE,CAAC;IACtF,OAAO,EAAE,GAAG,EAAE,CAAC,4DAA4D;CAC5E,CAAC,CAAA"}
|