Compare commits

...

9 Commits

Author SHA1 Message Date
Charlotte fb264b5a32
Merge 2fe1ea6c7f into 333567f481 2024-07-01 19:24:47 +05:00
Tulir Asokan 333567f481 Convert gif width/height to numbers 2024-06-19 14:29:21 +03:00
Tulir Asokan 125d057e44 Remove animated sticker pack check 2024-06-19 13:55:00 +03:00
Tulir Asokan e1038e7d1e Force proxying legacy federated downloads in giphy proxy 2024-06-19 12:30:14 +03:00
Tulir Asokan 850668a9f6 Update giphyproxy /version response 2024-06-19 12:21:04 +03:00
Tulir Asokan 804014f3b4 Add cats to giphy proxy 2024-06-19 12:02:52 +03:00
Tulir Asokan 5da539ad84 Add MSC3916-compatible giphy media repo proxy 2024-06-19 11:51:29 +03:00
Tulir Asokan 6332613e13 Don't try to use non-existent variables 2024-06-17 22:48:15 +03:00
Charlotte 🦝 Delenk 2fe1ea6c7f
Make Element Desktop send telegram sticker info
Element Desktop removes additional properties in the sticker info, but
not the media info. Element Android removes them in both currently. This
commit moves the net.maunium.telegram.sticker property to the media
info. This can be combined with a change to mautrix-telegram that
bridges telegram-imported matrix stickers to matrix stickers.
2022-08-23 08:12:07 +01:00
10 changed files with 197 additions and 12 deletions

10
.gitlab-ci.yml Normal file
View File

@ -0,0 +1,10 @@
build giphy proxy docker:
image: docker:stable
stage: build
before_script:
- docker login -u $CI_REGISTRY_USER -p $CI_REGISTRY_PASSWORD $CI_REGISTRY
script:
- docker build -t $CI_REGISTRY_IMAGE/giphyproxy:latest giphyproxy
- docker push $CI_REGISTRY_IMAGE/giphyproxy:latest
only:
- master

16
giphyproxy/Dockerfile Normal file
View File

@ -0,0 +1,16 @@
FROM golang:1-alpine AS builder
RUN apk add --no-cache ca-certificates
WORKDIR /build/giphyproxy
COPY . /build/giphyproxy
ENV CGO_ENABLED=0
RUN go build -o /usr/bin/giphyproxy
FROM scratch
COPY --from=builder /etc/ssl/certs/ca-certificates.crt /etc/ssl/certs/
COPY --from=builder /usr/bin/giphyproxy /usr/bin/giphyproxy
VOLUME /data
WORKDIR /data
CMD ["/usr/bin/giphyproxy"]

View File

@ -0,0 +1,17 @@
# The server name to use for the custom mxc:// URIs.
# This server name will effectively be a real Matrix server, it just won't implement anything other than media.
# You must either set up .well-known delegation from this domain to this program, or proxy the domain directly to this program.
server_name: giphy.example.com
# Optionally a custom .well-known response. This defaults to `server_name:443` if empty.
well_known_response:
# The proxy will use MSC3860/MSC3916 media download redirects if the requester supports it.
# Optionally, you can force redirects and not allow proxying at all by setting this to false.
allow_proxy: false
# Matrix server signing key to make the federation tester pass, same format as synapse's .signing.key file.
# You can generate one using `giphyproxy -generate-key`.
server_key: CHANGE ME
# Hostname where the proxy should listen on
hostname: 0.0.0.0
# Port where the proxy should listen on
port: 8008

24
giphyproxy/go.mod Normal file
View File

@ -0,0 +1,24 @@
module go.mau.fi/stickerpicker/giphyproxy
go 1.22.3
require (
go.mau.fi/util v0.5.0
gopkg.in/yaml.v3 v3.0.1
maunium.net/go/mautrix v0.19.0-beta.1.0.20240619092812-451658374280
)
require (
github.com/gorilla/mux v1.8.0 // indirect
github.com/mattn/go-colorable v0.1.13 // indirect
github.com/mattn/go-isatty v0.0.19 // indirect
github.com/rs/zerolog v1.33.0 // indirect
github.com/tidwall/gjson v1.17.1 // indirect
github.com/tidwall/match v1.1.1 // indirect
github.com/tidwall/pretty v1.2.0 // indirect
github.com/tidwall/sjson v1.2.5 // indirect
golang.org/x/crypto v0.24.0 // indirect
golang.org/x/exp v0.0.0-20240613232115-7f521ea00fb8 // indirect
golang.org/x/net v0.26.0 // indirect
golang.org/x/sys v0.21.0 // indirect
)

47
giphyproxy/go.sum Normal file
View File

@ -0,0 +1,47 @@
github.com/coreos/go-systemd/v22 v22.5.0/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSVTIJ3seZv2GcEnc=
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/godbus/dbus/v5 v5.0.4/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA=
github.com/gorilla/mux v1.8.0 h1:i40aqfkR1h2SlN9hojwV5ZA91wcXFOvkdNIeFDP5koI=
github.com/gorilla/mux v1.8.0/go.mod h1:DVbg23sWSpFRCP0SfiEN6jmj59UnW/n46BH5rLB71So=
github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA=
github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg=
github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM=
github.com/mattn/go-isatty v0.0.19 h1:JITubQf0MOLdlGRuRq+jtsDlekdYPia9ZFsB8h/APPA=
github.com/mattn/go-isatty v0.0.19/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y=
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/rs/xid v1.5.0/go.mod h1:trrq9SKmegXys3aeAKXMUTdJsYXVwGY3RLcfgqegfbg=
github.com/rs/zerolog v1.33.0 h1:1cU2KZkvPxNyfgEmhHAz/1A9Bz+llsdYzklWFzgp0r8=
github.com/rs/zerolog v1.33.0/go.mod h1:/7mN4D5sKwJLZQ2b/znpjC3/GQWY/xaDXUM0kKWRHss=
github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg=
github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
github.com/tidwall/gjson v1.14.2/go.mod h1:/wbyibRr2FHMks5tjHJ5F8dMZh3AcwJEMf5vlfC0lxk=
github.com/tidwall/gjson v1.17.1 h1:wlYEnwqAHgzmhNUFfw7Xalt2JzQvsMx2Se4PcoFCT/U=
github.com/tidwall/gjson v1.17.1/go.mod h1:/wbyibRr2FHMks5tjHJ5F8dMZh3AcwJEMf5vlfC0lxk=
github.com/tidwall/match v1.1.1 h1:+Ho715JplO36QYgwN9PGYNhgZvoUSc9X2c80KVTi+GA=
github.com/tidwall/match v1.1.1/go.mod h1:eRSPERbgtNPcGhD8UCthc6PmLEQXEWd3PRB5JTxsfmM=
github.com/tidwall/pretty v1.2.0 h1:RWIZEg2iJ8/g6fDDYzMpobmaoGh5OLl4AXtGUGPcqCs=
github.com/tidwall/pretty v1.2.0/go.mod h1:ITEVvHYasfjBbM0u2Pg8T2nJnzm8xPwvNhhsoaGGjNU=
github.com/tidwall/sjson v1.2.5 h1:kLy8mja+1c9jlljvWTlSazM7cKDRfJuR/bOJhcY5NcY=
github.com/tidwall/sjson v1.2.5/go.mod h1:Fvgq9kS/6ociJEDnK0Fk1cpYF4FIW6ZF7LAe+6jwd28=
go.mau.fi/util v0.5.0 h1:8yELAl+1CDRrwGe9NUmREgVclSs26Z68pTWePHVxuDo=
go.mau.fi/util v0.5.0/go.mod h1:DsJzUrJAG53lCZnnYvq9/mOyLuPScWwYhvETiTrpdP4=
golang.org/x/crypto v0.24.0 h1:mnl8DM0o513X8fdIkmyFE/5hTYxbwYOjDS/+rK6qpRI=
golang.org/x/crypto v0.24.0/go.mod h1:Z1PMYSOR5nyMcyAVAIQSKCDwalqy85Aqn1x3Ws4L5DM=
golang.org/x/exp v0.0.0-20240613232115-7f521ea00fb8 h1:yixxcjnhBmY0nkL253HFVIm0JsFHwrHdT3Yh6szTnfY=
golang.org/x/exp v0.0.0-20240613232115-7f521ea00fb8/go.mod h1:jj3sYF3dwk5D+ghuXyeI3r5MFf+NT2An6/9dOA95KSI=
golang.org/x/net v0.26.0 h1:soB7SVo0PWrY4vPW/+ay0jKDNScG2X9wFeYlXIvJsOQ=
golang.org/x/net v0.26.0/go.mod h1:5YKkiSynbBIh3p6iOc/vibscux0x38BZDkn8sCUPxHE=
golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.12.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.21.0 h1:rF+pYz3DAGSQAxAu1CbC7catZg4ebC4UIeIhKxBZvws=
golang.org/x/sys v0.21.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
maunium.net/go/mautrix v0.19.0-beta.1.0.20240619092812-451658374280 h1:+EHJF8h7obPow7kDnsmGoWN+bTCjHGxCKaH99MldZUI=
maunium.net/go/mautrix v0.19.0-beta.1.0.20240619092812-451658374280/go.mod h1:cxv1w6+syudmEpOewHYIQT9yO7TM5UOWmf6xEBVI4H4=

72
giphyproxy/main.go Normal file
View File

@ -0,0 +1,72 @@
// maunium-stickerpicker - A fast and simple Matrix sticker picker widget.
// Copyright (C) 2024 Tulir Asokan
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with this program. If not, see <https://www.gnu.org/licenses/>.
package main
import (
"context"
"flag"
"fmt"
"os"
"regexp"
"time"
"go.mau.fi/util/exerrors"
"gopkg.in/yaml.v3"
"maunium.net/go/mautrix/federation"
"maunium.net/go/mautrix/mediaproxy"
)
type Config struct {
mediaproxy.BasicConfig `yaml:",inline"`
mediaproxy.ServerConfig `yaml:",inline"`
}
var configPath = flag.String("config", "config.yaml", "config file path")
var generateServerKey = flag.Bool("generate-key", false, "generate a new server key and exit")
var giphyIDRegex = regexp.MustCompile(`^[a-zA-Z0-9-_]+$`)
func main() {
flag.Parse()
if *generateServerKey {
fmt.Println(federation.GenerateSigningKey().SynapseString())
} else {
cfgFile := exerrors.Must(os.ReadFile(*configPath))
var cfg Config
exerrors.PanicIfNotNil(yaml.Unmarshal(cfgFile, &cfg))
mp := exerrors.Must(mediaproxy.NewFromConfig(cfg.BasicConfig, getMedia))
mp.KeyServer.Version.Name = "maunium-stickerpicker giphy proxy"
mp.ForceProxyLegacyFederation = true
exerrors.PanicIfNotNil(mp.Listen(cfg.ServerConfig))
}
}
func getMedia(_ context.Context, id string) (response mediaproxy.GetMediaResponse, err error) {
// This is not related to giphy, but random cats are always fun
if id == "cat" {
return &mediaproxy.GetMediaResponseURL{
URL: "https://cataas.com/cat",
ExpiresAt: time.Now(),
}, nil
}
if !giphyIDRegex.MatchString(id) {
return nil, mediaproxy.ErrInvalidMediaIDSyntax
}
return &mediaproxy.GetMediaResponseURL{
URL: fmt.Sprintf("https://i.giphy.com/%s.webp", id),
}, nil
}

View File

@ -68,8 +68,6 @@ async def load_config(path: str) -> None:
"homeserver": homeserver_url, "homeserver": homeserver_url,
"user_id": user_id, "user_id": user_id,
"access_token": access_token, "access_token": access_token,
"giphy_api_key": giphy_api_key,
"giphy_mxc_prefix": giphy_mxc_prefix,
}, config_file) }, config_file)
print(f"Wrote config to {path}") print(f"Wrote config to {path}")

View File

@ -45,7 +45,7 @@ def add_meta(document: Document, info: matrix.StickerInfo, pack: StickerSetFull)
if isinstance(attr, DocumentAttributeSticker): if isinstance(attr, DocumentAttributeSticker):
info["body"] = attr.alt info["body"] = attr.alt
info["id"] = f"tg-{document.id}" info["id"] = f"tg-{document.id}"
info["net.maunium.telegram.sticker"] = { info["info"]["net.maunium.telegram.sticker"] = {
"pack": { "pack": {
"id": str(pack.set.id), "id": str(pack.set.id),
"short_name": pack.set.short_name, "short_name": pack.set.short_name,
@ -56,10 +56,6 @@ def add_meta(document: Document, info: matrix.StickerInfo, pack: StickerSetFull)
async def reupload_pack(client: TelegramClient, pack: StickerSetFull, output_dir: str) -> None: async def reupload_pack(client: TelegramClient, pack: StickerSetFull, output_dir: str) -> None:
if pack.set.animated:
print("Animated stickerpacks are currently not supported")
return
pack_path = os.path.join(output_dir, f"{pack.set.short_name}.json") pack_path = os.path.join(output_dir, f"{pack.set.short_name}.json")
try: try:
os.mkdir(os.path.dirname(pack_path)) os.mkdir(os.path.dirname(pack_path))
@ -73,7 +69,7 @@ async def reupload_pack(client: TelegramClient, pack: StickerSetFull, output_dir
try: try:
with util.open_utf8(pack_path) as pack_file: with util.open_utf8(pack_path) as pack_file:
existing_pack = json.load(pack_file) existing_pack = json.load(pack_file)
already_uploaded = {int(sticker["net.maunium.telegram.sticker"]["id"]): sticker already_uploaded = {int(sticker["info"]["net.maunium.telegram.sticker"]["id"]): sticker
for sticker in existing_pack["stickers"]} for sticker in existing_pack["stickers"]}
print(f"Found {len(already_uploaded)} already reuploaded stickers") print(f"Found {len(already_uploaded)} already reuploaded stickers")
except FileNotFoundError: except FileNotFoundError:
@ -97,7 +93,7 @@ async def reupload_pack(client: TelegramClient, pack: StickerSetFull, output_dir
# If there was no sticker metadata, use the first emoji we find # If there was no sticker metadata, use the first emoji we find
if doc["body"] == "": if doc["body"] == "":
doc["body"] = sticker.emoticon doc["body"] = sticker.emoticon
doc["net.maunium.telegram.sticker"]["emoticons"].append(sticker.emoticon) doc["info"]["net.maunium.telegram.sticker"]["emoticons"].append(sticker.emoticon)
with util.open_utf8(pack_path, "w") as pack_file: with util.open_utf8(pack_path, "w") as pack_file:
json.dump({ json.dump({

View File

@ -68,9 +68,9 @@ export class GiphySearchTab extends Component {
widgetAPI.sendSticker({ widgetAPI.sendSticker({
"body": gif.title, "body": gif.title,
"info": { "info": {
"h": gif.images.original.height, "h": +gif.images.original.height,
"w": gif.images.original.width, "w": +gif.images.original.width,
"size": gif.images.original.size, "size": +gif.images.original.size,
"mimetype": "image/webp", "mimetype": "image/webp",
}, },
"msgtype": "m.image", "msgtype": "m.image",

View File

@ -47,6 +47,11 @@ window.onmessage = event => {
} }
export function sendSticker(content) { export function sendSticker(content) {
if (content["info"]["net.maunium.telegram.sticker"] === undefined) {
// Old sticker, move the property to its new location
content["info"]["net.maunium.telegram.sticker"] = content["net.maunium.telegram.sticker"];
delete content["net.maunium.telegram.sticker"];
}
const data = { const data = {
content: { ...content }, content: { ...content },
// `name` is for Element Web (and also the spec) // `name` is for Element Web (and also the spec)