Skip to content

Commit 1c5d427

Browse files
authored
try to validate assets before committing them (#10480)
1 parent 00ede41 commit 1c5d427

File tree

2 files changed

+71
-8
lines changed

2 files changed

+71
-8
lines changed

pxtlib/spriteutils.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -145,7 +145,7 @@ namespace pxt.sprite {
145145
}
146146
}
147147

148-
protected dataLength() {
148+
dataLength() {
149149
return Math.ceil(this.width * this.height / 2);
150150
}
151151
}
@@ -179,7 +179,7 @@ namespace pxt.sprite {
179179
this.buf[index] = value;
180180
}
181181

182-
protected dataLength() {
182+
dataLength() {
183183
return this.width * this.height;
184184
}
185185
}

pxtlib/tilemap.ts

Lines changed: 69 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -154,6 +154,12 @@ namespace pxt {
154154
const existing = this.lookupByID(id);
155155

156156
if (!assetEquals(existing, newValue)) {
157+
if (!validateAsset(newValue) && validateAsset(existing)) {
158+
pxt.warn("Refusing to overwrite asset with invalid version");
159+
pxt.tickEvent("assets.invalidAssetOverwrite", { assetType: newValue.type });
160+
return existing;
161+
}
162+
157163
this.removeByID(id);
158164
asset = this.add(newValue);
159165
this.notifyListener(newValue.internalID);
@@ -1948,6 +1954,69 @@ namespace pxt {
19481954
return getShortIDCore(asset.type, asset.id);
19491955
}
19501956

1957+
export function validateAsset(asset: pxt.Asset) {
1958+
if (!asset) return false;
1959+
1960+
switch (asset.type) {
1961+
case AssetType.Image:
1962+
case AssetType.Tile:
1963+
return validateImageAsset(asset as ProjectImage | Tile);
1964+
case AssetType.Tilemap:
1965+
return validateTilemap(asset as ProjectTilemap);
1966+
case AssetType.Animation:
1967+
return validateAnimation(asset as Animation)
1968+
case AssetType.Song:
1969+
return validateSong(asset as Song);
1970+
}
1971+
}
1972+
1973+
function validateImageAsset(asset: ProjectImage | Tile) {
1974+
if (!asset.bitmap) return false;
1975+
1976+
return validateBitmap(sprite.Bitmap.fromData(asset.bitmap));
1977+
}
1978+
1979+
function validateTilemap(tilemap: ProjectTilemap) {
1980+
if (
1981+
!tilemap.data ||
1982+
!tilemap.data.tilemap ||
1983+
!tilemap.data.tileset ||
1984+
!tilemap.data.tileset.tileWidth ||
1985+
!tilemap.data.tileset.tiles?.length ||
1986+
!tilemap.data.layers
1987+
) {
1988+
return false;
1989+
}
1990+
1991+
return validateBitmap(sprite.Bitmap.fromData(tilemap.data.layers)) &&
1992+
validateBitmap(tilemap.data.tilemap);
1993+
}
1994+
1995+
function validateAnimation(animation: Animation) {
1996+
if (!animation.frames?.length || animation.interval <= 0) {
1997+
return false;
1998+
}
1999+
2000+
return !animation.frames.some(frame => !validateBitmap(sprite.Bitmap.fromData(frame)));
2001+
}
2002+
2003+
function validateBitmap(bitmap: sprite.Bitmap) {
2004+
return bitmap.width > 0 &&
2005+
bitmap.height > 0 &&
2006+
!Number.isNaN(bitmap.x0) &&
2007+
!Number.isNaN(bitmap.y0) &&
2008+
bitmap.data().data.length === bitmap.dataLength();
2009+
}
2010+
2011+
function validateSong(song: Song) {
2012+
return song.song &&
2013+
song.song.ticksPerBeat > 0 &&
2014+
song.song.beatsPerMeasure > 0 &&
2015+
song.song.measures > 0 &&
2016+
song.song.beatsPerMinute > 0 &&
2017+
!!song.song.tracks;
2018+
}
2019+
19512020
function getShortIDCore(assetType: pxt.AssetType, id: string, allowNoPrefix = false) {
19522021
let prefix: string;
19532022
switch (assetType) {
@@ -2062,12 +2131,6 @@ namespace pxt {
20622131
}
20632132
}
20642133

2065-
2066-
function set16Bit(buf: Uint8ClampedArray, offset: number, value: number) {
2067-
buf[offset] = value & 0xff;
2068-
buf[offset + 1] = (value >> 8) & 0xff;
2069-
}
2070-
20712134
function read16Bit(buf: Uint8ClampedArray, offset: number) {
20722135
return buf[offset] | (buf[offset + 1] << 8)
20732136
}

0 commit comments

Comments
 (0)