Documentation for nanogram available here for awhile

Edit: Dont be a ungrateful Be nice pls. I put a lot of time, effort, and my own money into making this. I’m choosing to freely share it :)

Yes I get help from LLM’s. Review the code if you think it’s unsafe, or just move on and don’t use it. Happy to answer any technical questions.

Edit 2: Expanded source code for termux version here.

Edit 3: Expanded source for pi version here

  • SavvyWolf@pawb.social
    link
    fedilink
    English
    arrow-up
    1
    ·
    1 day ago

    Had a quick skim and found this little guy:

    # ---------- Protected media route ----------
    @app.route('/img/<path:name>')
    @login_required
    def media(name):
        db = SessionLocal()
        try:
            me = current_user(db)
            # Find the post with this image
            post = db.query(Post).filter_by(image_path=name).first()
            if post:
                # Check visibility
                can_view = post.user_id == me.id or db.query(UserVisibility).filter_by(
                    owner_id=post.user_id, viewer_id=me.id
                ).first() is not None
                if not can_view:
                    abort(403)
            return send_from_directory(UPLOAD_DIR, os.path.basename(name))
        finally:
            db.close()
    

    I’ve not read through everything, but there are some security concerns that jump out to me from just this function. Hopefully you can enlighten me on them.

    Firstly, what is stopping a logged in user from accessing any image that, for whatever reason, doesn’t have an associated post for it?

    Secondly, the return codes for “the image doesn’t exist” (404) and “the image exists but you can’t access it” (403) look to be different. This means that a logged in user can check whether a given filename (e.g. “epstien_and_trump_cuddling.jpg”) has been uploaded or not by any user.

    Both of these look to be pretty bad security issues, especially for a project touting its ability to protect from nationstates. Am I missing something?

    • hereforawhile@lemmy.mlOP
      link
      fedilink
      English
      arrow-up
      1
      arrow-down
      1
      ·
      edit-2
      1 day ago
      1. I disclaim the opposite, I don’t tout its ability against nation states in the Readme.

      1. There are two checks for someone on the server to be able to view a post. First, are you a valid user? Then did the person sharing the photo give you access to view their posts? If both are true you can see the post. Also, on upload to the server, the image get compressed and stripped of any meta data including the file name…so no they couldn’t check a file name. Each photo is given a randomly generated filename.

      Edit.

      1. There can’t be any posts without images attached. There will always be a post and an image. (unless it’s a 1-1 DM or group chat) which has its own rules for access.
      • SavvyWolf@pawb.social
        link
        fedilink
        English
        arrow-up
        1
        ·
        7 hours ago
        1. You list “Activist/journalist secure communication” as a use case. Not all countries have freedom of press.

        2. Looks like you name images based on a random uuid, so that should protect against filename attacks. But if you do have a filename you can tell whether the image has been an image or not.

        Also, looks like all uploads are converted to jpg, regardless as to whether the original image was a jpg (or even an image) or not. Don’t do that.

        1. Can you point to where in code this invariant is enforced?
        • hereforawhile@lemmy.mlOP
          link
          fedilink
          English
          arrow-up
          1
          ·
          7 hours ago
          1. You list “Activist/journalist secure communication” as a use case. Not all countries have freedom of press.

          Is that an inaccurate claim? It should provide the means to organize and communicate securely…to the extent Tor is secure, and if your using the official Tor browser, web crypto can be utilized for group and 1-1s for an additional layer of encryption. I thought it was a fine claim. It should be able to handle quite a few people messaging all at once on the PI varient.

          1. Looks like you name images based on a random uuid, so that should protect against filename attacks. But if you do have a filename you can tell whether the image has been an image or not.

          How would you ever discover a filename?

          If you did have a filename and the exact url to the image you would need to be logged in as a valid user, and the person who shared the photo would have needed to allow access to their profile.

          Even if you have the correct link, if those two conditions arnt satisfied you will not be able to view.

          Also, looks like all uploads are converted to jpg, regardless as to whether the original image was a jpg (or even an image) or not. Don’t do that.

          This was a design choice to have consistency in filetypes. What’s the downside? All browsers will support displaying a jpg.

          1. Can you point to where in code this invariant is enforced?

          Which part are you talking about? The image compression is defined as the compress and store function.

          The “API reference” in the readme goes into further specifics on how this works with flask.

          Everything except the login page, registration link will behind these two checks see (def login) where the @loginrequired logic is defined for each of the app routes.