From eed971d9972a88dea08c4c52a8b2a007f4072a6e Mon Sep 17 00:00:00 2001 From: Noah Petherbridge Date: Wed, 10 Jan 2024 20:47:38 -0800 Subject: [PATCH] FAQ update and notifications fix --- pkg/controller/api/likes.go | 17 ++++++++------ pkg/controller/friend/request.go | 5 ++++ pkg/models/friend.go | 19 ++++++++++++++++ pkg/models/private_photo.go | 19 ++++++++++++++++ web/templates/faq.html | 39 ++++++++++++++++++++------------ 5 files changed, 77 insertions(+), 22 deletions(-) diff --git a/pkg/controller/api/likes.go b/pkg/controller/api/likes.go index 3a8ddc3..6b11835 100644 --- a/pkg/controller/api/likes.go +++ b/pkg/controller/api/likes.go @@ -96,25 +96,28 @@ func Likes() http.HandlerFunc { case "photos": if photo, err := models.GetPhoto(tableID); err == nil { if user, err := models.GetUser(photo.UserID); err == nil { - // Admin safety check: in case the admin clicked 'Like' on a friends-only or private - // picture they shouldn't have been expected to see, do not log a like. - if currentUser.IsAdmin && currentUser.ID != user.ID { + // Safety check: if the current user should not see this picture, they can not "Like" it. + // Example: you unfriended them but they still had the image on their old browser page. + var unallowed bool + if currentUser.ID != user.ID { if (photo.Visibility == models.PhotoFriends && !models.AreFriends(user.ID, currentUser.ID)) || (photo.Visibility == models.PhotoPrivate && !models.IsPrivateUnlocked(user.ID, currentUser.ID)) { - SendJSON(w, http.StatusForbidden, Response{ - Error: "You are not allowed to like that photo.", - }) - return + unallowed = true } } // Blocking safety check: if either user blocks the other, liking is not allowed. if models.IsBlocking(currentUser.ID, user.ID) { + unallowed = true + } + + if unallowed { SendJSON(w, http.StatusForbidden, Response{ Error: "You are not allowed to like that photo.", }) return } + targetUser = user } } else { diff --git a/pkg/controller/friend/request.go b/pkg/controller/friend/request.go index ee0d54f..05548f2 100644 --- a/pkg/controller/friend/request.go +++ b/pkg/controller/friend/request.go @@ -60,6 +60,11 @@ func AddFriend() http.HandlerFunc { return } + // Revoke any friends-only photo notifications they had received before. + if err := models.RevokeFriendPhotoNotifications(currentUser, user.ID); err != nil { + log.Error("Couldn't revoke friend photo notifications from %s to %s: %s", currentUser.Username, user.Username, err) + } + var message string if verdict == "reject" { message = fmt.Sprintf("Friend request from %s has been rejected.", username) diff --git a/pkg/models/friend.go b/pkg/models/friend.go index b2d890b..6587160 100644 --- a/pkg/models/friend.go +++ b/pkg/models/friend.go @@ -446,6 +446,25 @@ func RemoveFriend(sourceUserID, targetUserID uint64) error { return result.Error } +// RevokeFriendPhotoNotifications removes notifications about newly uploaded friends photos +// that were sent to your former friends, when you remove their friendship. +// +// For example: if I unfriend you, all your past notifications that showed my friends-only photos should +// be revoked so that you can't see them anymore. +func RevokeFriendPhotoNotifications(currentUser *User, fromUserID uint64) error { + // Gather the IDs of all our private photos to nuke notifications for. + photoIDs, err := currentUser.AllFriendsOnlyPhotoIDs() + if err != nil { + return err + } else if len(photoIDs) == 0 { + // Nothing to do. + return nil + } + + log.Info("RevokeFriendPhotoNotifications(%s): forget about friend photo uploads for user %d on photo IDs: %v", currentUser.Username, fromUserID, photoIDs) + return RemoveSpecificNotificationBulk(fromUserID, NotificationNewPhoto, "photos", photoIDs) +} + // Save photo. func (f *Friend) Save() error { result := DB.Save(f) diff --git a/pkg/models/private_photo.go b/pkg/models/private_photo.go index c6d8f2d..4396f07 100644 --- a/pkg/models/private_photo.go +++ b/pkg/models/private_photo.go @@ -100,6 +100,25 @@ func (u *User) AllPrivatePhotoIDs() ([]uint64, error) { return photoIDs, nil } +// AllFriendsOnlyPhotoIDs returns the listing of all IDs of the user's private photos. +func (u *User) AllFriendsOnlyPhotoIDs() ([]uint64, error) { + var photoIDs = []uint64{} + err := DB.Table( + "photos", + ).Select( + "photos.id AS id", + ).Where( + "user_id = ? AND visibility = ?", + u.ID, PhotoFriends, + ).Scan(&photoIDs) + + if err.Error != nil { + return photoIDs, fmt.Errorf("AllFriendsOnlyPhotoIDs(%s): %s", u.Username, err.Error) + } + + return photoIDs, nil +} + // AllPhotoIDs returns the listing of all IDs of the user's photos. func (u *User) AllPhotoIDs() ([]uint64, error) { if u.cachePhotoIDs != nil { diff --git a/web/templates/faq.html b/web/templates/faq.html index cc0537a..0315e7d 100644 --- a/web/templates/faq.html +++ b/web/templates/faq.html @@ -52,7 +52,7 @@
  • Can I include other people in my photos?
  • What is considered "explicit" in photos?
  • Are digitally altered or 'photoshopped' pictures okay?
  • -
  • Does this site prevent people from downloading my pictures?
  • +
  • Does this site prevent people from downloading my pictures? UPDATED Jan 10 2024
  • @@ -706,29 +706,38 @@

    Does this site prevent people from downloading my pictures?

    - This website does not go out of its way to prevent people from downloading pictures, and - nor will it pretend to. This is actually a very difficult problem to solve in the year {{.YYYY}}. + Updated Jan 10 2024

    - I could add some JavaScripts that prevent right-clicking on my pages so you can't - just "Save image as," but this would only deter desktop (mouse & keyboard) users and is easy - to work around. I could place a transparent image over top of all your pictures like - Instagram does and if you try and save it, you just get a one-pixel transparent GIF; but this - is trivially defeated by any novice web designer by just right-clicking, "Inspect element" and - deleting it from the web page to get at the photo it was protecting. + As of November 2023, the {{PrettyTitle}} website does discourage the downloading of pictures + to the limited extent that a web page is able to. We have a right-click handler (long press + on mobile) where if you right-click on a photo anywhere on the site, you are shown a pop-up + message to "please respect our members' privacy" and a reminder that it is against the rules + to download and share images from this site elsewhere. We also have a script that inteferes with + dragging an image off of the page and into your URL bar or another application which helps to + protect pictures from being easily saved.

    - And people can always just screenshot the whole web page - and a web page can't do anything - at all to prevent that. With mobile phones this is an especially easy and common thing to - do. Any mild measures this site could take to deter downloading would only provide a false - sense of security, which is worse than having no security. + You can see this in action by attempting to right-click, long press, or drag the image below:

    - There are risks inherent with putting a picture on the Internet. This website does provide - some controls you can utilize as to who will see the pictures you upload: + +

    + +

    + However, a motivated individual can always circumvent these kind of restrictions + and download a picture if they really want to. There is no technical measure that a website can + take to prevent this entirely: because at the end of the day, they can always just screenshot the whole + entire web page which is especially trivial and common to do from mobile devices. +

    + +

    + There are risks inherent with putting a picture on the Internet. This website does provide + some controls you can utilize to limit who is allowed to see your picture in the first place, to + those who you think you can trust not to download your picture: