From 782c965781afea8c5ef094ccdcbdcf514fd02c49 Mon Sep 17 00:00:00 2001 From: =?utf8?q?David=20=E2=80=98Bombe=E2=80=99=20Roden?= Date: Fri, 25 Oct 2013 07:31:41 +0200 Subject: [PATCH] Verify that the avatar ID belongs to an image of the Sone. --- .../net/pterodactylus/sone/core/SoneParser.java | 121 +++++++++--------- .../pterodactylus/sone/core/SoneParserTest.java | 6 + src/test/resources/sone-parser/invalid-avatar.xml | 136 +++++++++++++++++++++ 3 files changed, 207 insertions(+), 56 deletions(-) create mode 100644 src/test/resources/sone-parser/invalid-avatar.xml diff --git a/src/main/java/net/pterodactylus/sone/core/SoneParser.java b/src/main/java/net/pterodactylus/sone/core/SoneParser.java index 9e926d4..38b21e3 100644 --- a/src/main/java/net/pterodactylus/sone/core/SoneParser.java +++ b/src/main/java/net/pterodactylus/sone/core/SoneParser.java @@ -48,6 +48,7 @@ import net.pterodactylus.util.xml.XML; import com.google.common.base.Optional; import com.google.common.collect.Maps; +import com.google.common.collect.Sets; import com.google.common.primitives.Ints; import org.w3c.dom.Document; @@ -100,6 +101,61 @@ public class SoneParser { throw new MalformedXml(); } + /* parse albums. */ + SimpleXML albumsXml = soneXml.getNode("albums"); + Map albums = Maps.newHashMap(); + Set images = Sets.newHashSet(); + if (albumsXml != null) { + for (SimpleXML albumXml : albumsXml.getNodes("album")) { + String id = albumXml.getValue("id", null); + String parentId = albumXml.getValue("parent", null); + String title = albumXml.getValue("title", null); + String description = albumXml.getValue("description", ""); + String albumImageId = albumXml.getValue("album-image", null); + if ((id == null) || (title == null) || (description == null)) { + logger.log(Level.WARNING, String.format("Downloaded Sone %s contains invalid album!", sone)); + throw new MalformedXml(); + } + Album parent = sone.getRootAlbum(); + if (parentId != null) { + parent = albums.get(parentId); + if (parent == null) { + logger.log(Level.WARNING, String.format("Downloaded Sone %s has album with invalid parent!", sone)); + throw new InvalidParentAlbum(); + } + } + Album album = parent.newAlbumBuilder().withId(id).build().modify().setTitle(title).setDescription(description).update(); + albums.put(album.getId(), album); + SimpleXML imagesXml = albumXml.getNode("images"); + if (imagesXml != null) { + for (SimpleXML imageXml : imagesXml.getNodes("image")) { + String imageId = imageXml.getValue("id", null); + String imageCreationTimeString = imageXml.getValue("creation-time", null); + String imageKey = imageXml.getValue("key", null); + String imageTitle = imageXml.getValue("title", null); + String imageDescription = imageXml.getValue("description", ""); + String imageWidthString = imageXml.getValue("width", null); + String imageHeightString = imageXml.getValue("height", null); + if ((imageId == null) || (imageCreationTimeString == null) || (imageKey == null) || (imageTitle == null) || (imageWidthString == null) || (imageHeightString == null)) { + logger.log(Level.WARNING, String.format("Downloaded Sone %s contains invalid images!", sone)); + throw new MalformedXml(); + } + long creationTime = Numbers.safeParseLong(imageCreationTimeString, 0L); + int imageWidth = Numbers.safeParseInteger(imageWidthString, 0); + int imageHeight = Numbers.safeParseInteger(imageHeightString, 0); + if ((imageWidth < 1) || (imageHeight < 1)) { + logger.log(Level.WARNING, String.format("Downloaded Sone %s contains image %s with invalid dimensions (%s, %s)!", sone, imageId, imageWidthString, imageHeightString)); + throw new MalformedDimension(); + } + Image image = album.newImageBuilder().withId(imageId).at(imageKey).created(creationTime).sized(imageWidth, imageHeight).build(Optional.absent()); + image.modify().setTitle(imageTitle).setDescription(imageDescription).update(); + images.add(imageId); + } + } + album.modify().setAlbumImage(albumImageId).update(); + } + } + /* parse profile. */ String profileFirstName = profileXml.getValue("first-name", null); String profileMiddleName = profileXml.getValue("middle-name", null); @@ -109,8 +165,13 @@ public class SoneParser { Integer profileBirthYear = Numbers.safeParseInteger(profileXml.getValue("birth-year", null)); Profile profile = new Profile(sone).modify().setFirstName(profileFirstName).setMiddleName(profileMiddleName).setLastName(profileLastName).update(); profile.modify().setBirthDay(profileBirthDay).setBirthMonth(profileBirthMonth).setBirthYear(profileBirthYear).update(); + /* avatar is processed after images are loaded. */ String avatarId = profileXml.getValue("avatar", null); + if ((avatarId != null) && !images.contains(avatarId)) { + throw new InvalidAvatarId(); + } + profile.setAvatar(fromNullable(avatarId)); /* parse profile fields. */ SimpleXML profileFieldsXml = profileXml.getNode("fields"); @@ -219,62 +280,6 @@ public class SoneParser { } } - /* parse albums. */ - SimpleXML albumsXml = soneXml.getNode("albums"); - Map albums = Maps.newHashMap(); - if (albumsXml != null) { - for (SimpleXML albumXml : albumsXml.getNodes("album")) { - String id = albumXml.getValue("id", null); - String parentId = albumXml.getValue("parent", null); - String title = albumXml.getValue("title", null); - String description = albumXml.getValue("description", ""); - String albumImageId = albumXml.getValue("album-image", null); - if ((id == null) || (title == null) || (description == null)) { - logger.log(Level.WARNING, String.format("Downloaded Sone %s contains invalid album!", sone)); - throw new MalformedXml(); - } - Album parent = sone.getRootAlbum(); - if (parentId != null) { - parent = albums.get(parentId); - if (parent == null) { - logger.log(Level.WARNING, String.format("Downloaded Sone %s has album with invalid parent!", sone)); - throw new InvalidParentAlbum(); - } - } - Album album = parent.newAlbumBuilder().withId(id).build().modify().setTitle(title).setDescription(description).update(); - albums.put(album.getId(), album); - SimpleXML imagesXml = albumXml.getNode("images"); - if (imagesXml != null) { - for (SimpleXML imageXml : imagesXml.getNodes("image")) { - String imageId = imageXml.getValue("id", null); - String imageCreationTimeString = imageXml.getValue("creation-time", null); - String imageKey = imageXml.getValue("key", null); - String imageTitle = imageXml.getValue("title", null); - String imageDescription = imageXml.getValue("description", ""); - String imageWidthString = imageXml.getValue("width", null); - String imageHeightString = imageXml.getValue("height", null); - if ((imageId == null) || (imageCreationTimeString == null) || (imageKey == null) || (imageTitle == null) || (imageWidthString == null) || (imageHeightString == null)) { - logger.log(Level.WARNING, String.format("Downloaded Sone %s contains invalid images!", sone)); - throw new MalformedXml(); - } - long creationTime = Numbers.safeParseLong(imageCreationTimeString, 0L); - int imageWidth = Numbers.safeParseInteger(imageWidthString, 0); - int imageHeight = Numbers.safeParseInteger(imageHeightString, 0); - if ((imageWidth < 1) || (imageHeight < 1)) { - logger.log(Level.WARNING, String.format("Downloaded Sone %s contains image %s with invalid dimensions (%s, %s)!", sone, imageId, imageWidthString, imageHeightString)); - throw new MalformedDimension(); - } - Image image = album.newImageBuilder().withId(imageId).at(imageKey).created(creationTime).sized(imageWidth, imageHeight).build(Optional.absent()); - image = image.modify().setTitle(imageTitle).setDescription(imageDescription).update(); - } - } - album.modify().setAlbumImage(albumImageId).update(); - } - } - - /* process avatar. */ - profile.setAvatar(fromNullable(avatarId)); - /* okay, apparently everything was parsed correctly. Now import. */ sone.setProfile(profile); sone.setPosts(posts); @@ -354,6 +359,10 @@ public class SoneParser { } + public static class InvalidAvatarId extends RuntimeException { + + } + public static class DuplicateField extends RuntimeException { } diff --git a/src/test/java/net/pterodactylus/sone/core/SoneParserTest.java b/src/test/java/net/pterodactylus/sone/core/SoneParserTest.java index 03bce54..19e5ae2 100644 --- a/src/test/java/net/pterodactylus/sone/core/SoneParserTest.java +++ b/src/test/java/net/pterodactylus/sone/core/SoneParserTest.java @@ -18,6 +18,7 @@ import java.io.InputStream; import java.util.logging.Logger; import net.pterodactylus.sone.core.SoneParser.DuplicateField; +import net.pterodactylus.sone.core.SoneParser.InvalidAvatarId; import net.pterodactylus.sone.core.SoneParser.InvalidParentAlbum; import net.pterodactylus.sone.core.SoneParser.InvalidProtocolVersion; import net.pterodactylus.sone.core.SoneParser.InvalidXml; @@ -123,6 +124,11 @@ public class SoneParserTest { soneParser.parseSone(database, originalSone, getXml("duplicate-field")); } + @Test(expected = InvalidAvatarId.class) + public void verifyThatAnInvalidAvatarIdCausesAnError() { + soneParser.parseSone(database, originalSone, getXml("invalid-avatar")); + } + @Test public void verifyThatMissingPostsDoNotCauseAnError() { soneParser.parseSone(database, originalSone, getXml("missing-posts")); diff --git a/src/test/resources/sone-parser/invalid-avatar.xml b/src/test/resources/sone-parser/invalid-avatar.xml new file mode 100644 index 0000000..159b104 --- /dev/null +++ b/src/test/resources/sone-parser/invalid-avatar.xml @@ -0,0 +1,136 @@ + + + + + 0 + + + Sone + 0.8.7 + + + + First + M. + Last + 22 + 10 + 2013 + foo + + + Field1 + Value1 + + + Field2 + Value2 + + + + + + + bbb7ebf0-3adb-11e3-8a0b-630cd8f21cf3 + + + Hello, World! + + + d8c9586e-3adb-11e3-bb31-171fc040e645 + 0rpD4gL8mszav2trndhIdKIxvKUCNAe2kjA3dLV8CVU + + Hello, User! + + + + + + f09fa448-3adb-11e3-a783-ab54a11aacc4 + bbb7ebf0-3adb-11e3-8a0b-630cd8f21cf3 + + Talking to myself. + + + 0a376440-3adc-11e3-8f45-c7cc157436a5 + 11ebe86e-3adc-11e3-b7b9-7f2c88018a33 + + Talking to somebody I can't see. + + + + + bbb7ebf0-3adb-11e3-8a0b-630cd8f21cf3 + 305d85e6-3adc-11e3-be45-8b53dd91f0af + + + + f09fa448-3adb-11e3-a783-ab54a11aacc4 + 3ba28960-3adc-11e3-93c7-6713d170f44c + + + + + 6a73c6e6-3adc-11e3-b091-577b10a725ad + Album1 + First album with stuff. + e3707102-3adc-11e3-b828-9f4de99f0bc4 + + + 8966f69a-3adc-11e3-802d-0f57b63c8809 + 1382420473000 + SSK@JvW9oZ8AriNGbwBosJD1gyMdiMHc5AgSmhNBU1CmAb8,na1IPpMcYiZLaWSv9EWq9NcDPPGplQBw8kJsLobXIG4,AQACAAE/8966f69a-3adc-11e3-802d-0f57b63c8809.jpg + Stuff + Yes, it's stuff! + 640 + 480 + + + e3707102-3adc-11e3-b828-9f4de99f0bc4 + 1382420624000 + SSK@dM1er7A9tG242bG-Xxy0kmprD7YkqEDE9mrZ98C~L3E,Np3iWiaGyd~er86edP9ndpH3pPKk2owDmAT2TQZNBA0,AQACAAE/e3707102-3adc-11e3-b828-9f4de99f0bc4.jpg + More Stuff + Yes, it's more stuff! + 640 + 360 + + + + + 1e73b52a-3add-11e3-ba45-cb0c28da9c2a + 6a73c6e6-3adc-11e3-b091-577b10a725ad + Nested Album + Nested album with stuff. + 312182ba-3add-11e3-bd76-13e7278f0161 + + + 312182ba-3add-11e3-bd76-13e7278f0161 + 1382420756000 + SSK@0rpD4gL8mszav2trndhIdKIxvKUCNAe2kjA3dLV8CVU,2KP8WDSaQvyJ16pXBHQrE1vj~fAaYPIsk35lM-ec4B0,AQACAAE/312182ba-3add-11e3-bd76-13e7278f0161.jpg + Other Stuff + Yes, it's other stuff! + 640 + 272 + + + + + 8a04b5fa-3add-11e3-afe2-676e721c04bd + Avatars + The avatar collection. + 96431abe-3add-11e3-8a46-67047503bf6d + + + 96431abe-3add-11e3-8a46-67047503bf6d + 1382420923000 + SSK@v6Js3ZJBMB23IB0JvdgiPynHQBYEvkFSi3~D8RDdj3s,FfLhjRC4bqYLHVexT33Pv6agXl6Ft~TDhX1jIM5w2n4,AQACAAE/96431abe-3add-11e3-8a46-67047503bf6d.png + Avatar 1 + The first avatar. + 64 + 64 + + + + + + -- 2.7.4