This is an automated email from the ASF dual-hosted git repository.

humbedooh pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/incubator-ponymail-foal.git


The following commit(s) were added to refs/heads/master by this push:
     new f713437  Add gravatar proxy endpoint for end-user privacy
f713437 is described below

commit f713437473eafee544e83a53d0576d90da7cb251
Author: Daniel Gruno <[email protected]>
AuthorDate: Thu Oct 28 22:36:46 2021 +0200

    Add gravatar proxy endpoint for end-user privacy
---
 server/endpoints/gravatar.py | 84 ++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 84 insertions(+)

diff --git a/server/endpoints/gravatar.py b/server/endpoints/gravatar.py
new file mode 100644
index 0000000..207451d
--- /dev/null
+++ b/server/endpoints/gravatar.py
@@ -0,0 +1,84 @@
+#!/usr/bin/env python3
+# -*- coding: utf-8 -*-
+# Licensed to the Apache Software Foundation (ASF) under one or more
+# contributor license agreements.  See the NOTICE file distributed with
+# this work for additional information regarding copyright ownership.
+# The ASF licenses this file to You under the Apache License, Version 2.0
+# (the "License"); you may not use this file except in compliance with
+# the License.  You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+"""Caching proxy for Gravatars"""
+
+import plugins.server
+import aiohttp
+import aiohttp.web
+
+CACHE_LIMIT = 25000  # Store a maximum of 25,000 gravatars in memory at any 
given time (25k x 5kb ≃125mb)
+GRAVATAR_URL = "https://secure.gravatar.com/avatar/%s.png?s=96&r=g&d=mm";
+
+gravatars = []
+gravatar_cache = {}
+
+
+async def fetch_gravatar(gid):
+    headers = {"User-Agent": "Pony Mail Agent/0.1"}
+    fetch_url = GRAVATAR_URL % gid
+    # Fetch image and store internally
+    try:
+        async with aiohttp.client.request("GET", fetch_url, headers=headers) 
as rv:
+            img_data = await rv.read()
+            gravatars.append(gid)
+            gravatar_cache[gid] = img_data
+    except aiohttp.ClientError:  # Client error, bail.
+        pass
+
+
+async def gravatar_exists_in_db(session, gid):
+    res = await session.database.search(
+        index=session.database.dbs.mbox,
+        size=1,
+        body={"query": {"bool": {"must": [{"term": {"gravatar": gid}}]}}},
+    )
+    if res and len(res["hits"]["hits"]) == 1:
+        return True
+    return False
+
+
+async def process(server: plugins.server.BaseServer, session: dict, indata: 
dict) -> dict:
+    gid = indata.get("md5", "null")
+    # Ensure md5 hash is valid
+    if len(gid) != 32 or not all(b in "abcdef0123456789" for b in gid):
+        gid = "null"
+    # Valid and in cache??
+    in_cache = gid in gravatars
+    should_fetch = False
+    # If valid but not cached, check if gravatar exists in the pony mail db
+    if gid != "null" and not in_cache:
+        should_fetch = await gravatar_exists_in_db(session, gid)
+    # If valid and not in cache, fetch from gravatar.com
+    if not in_cache and should_fetch:
+        await fetch_gravatar(gid)
+        # If we've hit the cache limit, pop the oldest element.
+        if len(gravatars) > CACHE_LIMIT:
+            to_pop = gravatars.pop(0)
+            del gravatar_cache[to_pop]
+    # if in cache, serve it.
+    if gid in gravatars:
+        img = gravatar_cache[gid]
+        headers = {
+          "Cache-Control": "max-age=86400",  # Expire gravatar in one day
+        }
+        return aiohttp.web.Response(headers=headers, content_type="image/png", 
body=img)
+    return aiohttp.web.Response(content_type="text/plain", body="Could not 
fetch gravatar")
+
+
+def register(server: plugins.server.BaseServer):
+    return plugins.server.Endpoint(process)

Reply via email to