Permalink
Browse files

Use random hash ID for pictures

  • Loading branch information...
shred committed Jul 31, 2018
1 parent 843bdfb commit 58a0f9e5e2b00d35d0863c8155259d4983ef71eb
@@ -72,6 +72,7 @@
private Store image = new Store();
private SortedSet<Tag> tags = new TreeSet<>();
private CommentThread thread = new CommentThread();
private String hashId;
/**
* {@link GallerySection} this picture belongs to.
@@ -172,6 +173,13 @@
public CommentThread getThread() { return thread; }
public void setThread(CommentThread thread) { this.thread = thread; }
/**
* A random hash id, so the picture ID cannot be guessed.
*/
@Column(unique = true, nullable = false)
public String getHashId() { return hashId; }
public void setHashId(String hashId) { this.hashId = hashId; }
@Override
public boolean equals(Object obj) {
return obj != null && obj instanceof Picture && super.equals(obj);
@@ -28,4 +28,14 @@
*/
public interface PictureDao extends BaseDao<Picture> {
/**
* Fetches a {@link Picture} by its hash ID. If the picture was not found,
* {@code null} is returned.
*
* @param hashId
* Picture hash ID
* @return Picture or {@code null}
*/
Picture fetchByHashId(String hashId);
}
@@ -63,4 +63,12 @@ public Criteria criteria() {
return getCurrentSession().createCriteria(Picture.class);
}
@Override
public Picture fetchByHashId(String hashId) {
return getCurrentSession()
.createQuery("FROM Picture WHERE hashId=:hashId", Picture.class)
.setParameter("hashId", hashId)
.uniqueResult();
}
}
@@ -21,7 +21,11 @@
import java.awt.Dimension;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.Date;
import java.util.Random;
import java.util.TimeZone;
import javax.activation.DataSource;
@@ -65,10 +69,13 @@
private @Resource CommentService commentService;
private @Resource MimeTypeAnalyzer mimeTypeAnalyzer;
private long hashCounter = new Random().nextInt(); // int, to avoid number overflow
@Override
public Picture createNew() {
Picture picture = new Picture();
picture.getThread().setCommentable(true);
picture.setHashId(generatePictureHash());
return picture;
}
@@ -212,4 +219,24 @@ public void renumberPictures(GallerySection gallery) throws CillaServiceExceptio
}
}
/**
* Generates a (hopefully) unique picture hash ID for a new picture.
*
* @return Hash ID
*/
private String generatePictureHash() {
try {
MessageDigest digest = MessageDigest.getInstance("SHA-256");
digest.update(String.valueOf(System.nanoTime()).getBytes(StandardCharsets.UTF_8));
digest.update(String.valueOf(hashCounter++).getBytes(StandardCharsets.UTF_8));
StringBuilder sb = new StringBuilder();
for (byte b : digest.digest()) {
sb.append(String.format("%02x", b & 0xFF));
}
return sb.toString();
} catch (NoSuchAlgorithmException ex) {
throw new InternalError("Standard digest algorithm is missing in this VM", ex);
}
}
}
@@ -99,7 +99,7 @@ private void mergePictures(GallerySectionDto dto, GallerySection entity) throws
if (picDto.isPersisted()) {
picture = pictureDao.fetch(picDto.getId());
pictureAssembler.merge(picDto, picture);
picture.setSequence(sequence++);
picture.setSequence(sequence);
removables.remove(picture);
pictureService.updatePicture(
picture,
@@ -113,7 +113,7 @@ private void mergePictures(GallerySectionDto dto, GallerySection entity) throws
}
picture = new Picture();
picture.setSequence(sequence++);
picture.setSequence(sequence);
pictureAssembler.merge(picDto, picture);
pictureService.addPicture(
entity,
@@ -122,6 +122,8 @@ private void mergePictures(GallerySectionDto dto, GallerySection entity) throws
);
picDto.setId(picture.getId());
}
sequence++;
}
for (Picture picture : removables) {
@@ -50,6 +50,7 @@
public PictureDto assemble(Picture entity) throws CillaServiceException {
PictureDto dto = new PictureDto();
dto.setId(entity.getId());
dto.setHashId(entity.getHashId());
dto.setCreateDate(entity.getCreateDate());
dto.setCreateTimeZone(entity.getCreateTimeZone());
dto.setCreateTimeDefinition(entity.getCreateTimeDefinition());
@@ -78,6 +79,7 @@ public PictureDto assemble(Picture entity) throws CillaServiceException {
public void merge(PictureDto dto, Picture entity) throws CillaServiceException {
super.merge(dto, entity);
entity.setCreateDate(dto.getCreateDate());
entity.setHashId(dto.getHashId());
entity.setCreateTimeZone(dto.getCreateTimeZone());
entity.setCreateTimeDefinition(dto.getCreateTimeDefinition());
@@ -39,7 +39,6 @@
import org.shredzone.cilla.ws.exception.CillaServiceException;
import org.shredzone.commons.view.annotation.Optional;
import org.shredzone.commons.view.annotation.PathPart;
import org.shredzone.commons.view.annotation.Qualifier;
import org.shredzone.commons.view.annotation.View;
import org.shredzone.commons.view.annotation.ViewHandler;
import org.shredzone.commons.view.exception.PageNotFoundException;
@@ -68,12 +67,10 @@
* Shows a single picture of a gallery.
*/
@Framed
@View(pattern = "/show/gallery/${section.id}/picture/${picture.id}.html", signature = {"section", "picture"})
@View(pattern = "/ajax/gallery/${section.id}/picture/${picture.id}.html", signature = {"section", "picture"}, qualifier = "ajax")
@View(pattern = "/show/gallery/${section.id}/picture/${picture.hashId}.html", signature = {"section", "picture"})
public String galleryPictureView(
@PathPart("section.id") GallerySection section,
@PathPart("picture.id") Picture picture,
@Qualifier String qualifier,
@PathPart("picture.hashId") Picture picture,
HttpServletRequest req, HttpServletResponse resp)
throws ViewException {
if (!pageService.isVisible(section.getPage())) {
@@ -100,21 +97,17 @@ public String galleryPictureView(
req.setAttribute("picture", picture);
req.setAttribute("info", new PictureInfoModel(pictureList, current));
if ("ajax".equals(qualifier)) {
return "section/gallery/picture-ajax.jsp";
} else {
return "section/gallery/picture.jsp";
}
return "section/gallery/picture.jsp";
}
/**
* Shows a map of the location the picture was taken.
*/
@Framed
@View(pattern = "/show/gallery/${section.id}/map/${picture.id}.html", name="gallery.map")
@View(pattern = "/show/gallery/${section.id}/map/${picture.hashId}.html", name="gallery.map")
public String galleryMapView(
@PathPart("section.id") GallerySection section,
@PathPart("picture.id") Picture picture,
@PathPart("picture.hashId") Picture picture,
HttpServletRequest req, HttpServletResponse resp)
throws ViewException {
if (!pageService.isVisible(section.getPage())) {
@@ -140,10 +133,10 @@ public String galleryMapView(
/**
* Streams the picture of a gallery.
*/
@View(pattern = "/picture/${picture.id}-${#type}.${#suffix(picture.image.contentType)}", signature = {"picture", "#type"})
@View(pattern = "/picture/${picture.id}.${#suffix(picture.image.contentType)}", signature = {"picture"})
@View(pattern = "/picture/${picture.hashId}-${#type}.${#suffix(picture.image.contentType)}", signature = {"picture", "#type"})
@View(pattern = "/picture/${picture.hashId}.${#suffix(picture.image.contentType)}", signature = {"picture"})
public void pictureView(
@PathPart("picture.id") Picture picture,
@PathPart("picture.hashId") Picture picture,
@Optional @PathPart("#type") String type,
HttpServletRequest req, HttpServletResponse resp)
throws ViewException, CillaServiceException {
@@ -36,11 +36,7 @@
@Override
public Picture convert(String string) {
try {
return pictureDao.fetch(Long.parseLong(string));
} catch (NumberFormatException ex) {
return null;
}
return pictureDao.fetchByHashId(string);
}
}
@@ -57,6 +57,7 @@
private DataHandler uploadFile;
private List<String> tags = new ArrayList<>();
private boolean commentable;
private String hashId;
public Date getCreateDate() { return createDate; }
public void setCreateDate(Date createDate) { this.createDate = createDate; }
@@ -100,6 +101,10 @@
public DataHandler getUploadFile() { return uploadFile; }
public void setUploadFile(DataHandler uploadFile) { this.uploadFile = uploadFile; }
@NotNull
public String getHashId() { return hashId; }
public void setHashId(String hashId) { this.hashId = hashId; }
@Override
public boolean equals(Object obj) {
return obj != null && obj instanceof PictureDto && super.equals(obj);

0 comments on commit 58a0f9e

Please sign in to comment.