-
Notifications
You must be signed in to change notification settings - Fork 80
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Flag media as restricted on upload (MSC3911)
- Loading branch information
Showing
8 changed files
with
190 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,50 @@ | ||
package unstable | ||
|
||
import ( | ||
"net/http" | ||
|
||
"github.com/getsentry/sentry-go" | ||
"github.com/turt2live/matrix-media-repo/api/_apimeta" | ||
"github.com/turt2live/matrix-media-repo/api/_responses" | ||
v1 "github.com/turt2live/matrix-media-repo/api/v1" | ||
"github.com/turt2live/matrix-media-repo/common/rcontext" | ||
"github.com/turt2live/matrix-media-repo/database" | ||
"github.com/turt2live/matrix-media-repo/pipelines/pipeline_create" | ||
"github.com/turt2live/matrix-media-repo/util" | ||
) | ||
|
||
func ClientCreateMedia(r *http.Request, rctx rcontext.RequestContext, user _apimeta.UserInfo) interface{} { | ||
id, err := restrictAsyncMediaId(rctx, r.Host, user.UserId) | ||
if err != nil { | ||
rctx.Log.Error("Unexpected error creating media ID:", err) | ||
sentry.CaptureException(err) | ||
return _responses.InternalServerError("unexpected error") | ||
} | ||
|
||
return &v1.MediaCreatedResponse{ | ||
ContentUri: util.MxcUri(id.Origin, id.MediaId), | ||
ExpiresTs: id.ExpiresTs, | ||
} | ||
} | ||
|
||
func restrictAsyncMediaId(ctx rcontext.RequestContext, host string, userId string) (*database.DbExpiringMedia, error) { | ||
id, err := pipeline_create.Execute(ctx, host, userId, pipeline_create.DefaultExpirationTime) | ||
if err != nil { | ||
return nil, err | ||
} | ||
|
||
db := database.GetInstance().RestrictedMedia.Prepare(ctx) | ||
err = db.Insert(id.Origin, id.MediaId, database.RestrictedToUser, id.UserId) | ||
if err != nil { | ||
// Try to clean up the expiring record, but don't fail if it fails | ||
err2 := database.GetInstance().ExpiringMedia.Prepare(ctx).SetExpiry(id.Origin, id.MediaId, util.NowMillis()) | ||
if err2 != nil { | ||
ctx.Log.Warn("Non-fatal error when trying to clean up interstitial expiring media: ", err2) | ||
sentry.CaptureException(err2) | ||
} | ||
|
||
return nil, err | ||
} | ||
|
||
return id, nil | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,36 @@ | ||
package unstable | ||
|
||
import ( | ||
"net/http" | ||
|
||
"github.com/getsentry/sentry-go" | ||
"github.com/turt2live/matrix-media-repo/api/_apimeta" | ||
"github.com/turt2live/matrix-media-repo/api/_responses" | ||
"github.com/turt2live/matrix-media-repo/api/_routers" | ||
"github.com/turt2live/matrix-media-repo/api/r0" | ||
"github.com/turt2live/matrix-media-repo/common/rcontext" | ||
"github.com/turt2live/matrix-media-repo/util" | ||
) | ||
|
||
func ClientUploadMediaSync(r *http.Request, rctx rcontext.RequestContext, user _apimeta.UserInfo) interface{} { | ||
// We're a bit fancy here. Instead of mirroring the "upload sync" endpoint to include restricted media, we | ||
// internally create an async media ID then claim it immediately. | ||
|
||
id, err := restrictAsyncMediaId(rctx, r.Host, user.UserId) | ||
if err != nil { | ||
rctx.Log.Error("Unexpected error creating media ID:", err) | ||
sentry.CaptureException(err) | ||
return _responses.InternalServerError("unexpected error") | ||
} | ||
|
||
r = _routers.ForceSetParam("server", id.Origin, r) | ||
r = _routers.ForceSetParam("mediaId", id.MediaId, r) | ||
|
||
resp := r0.UploadMediaAsync(r, rctx, user) | ||
if _, ok := resp.(*r0.MediaUploadedResponse); ok { | ||
return &r0.MediaUploadedResponse{ | ||
ContentUri: util.MxcUri(id.Origin, id.MediaId), | ||
} | ||
} | ||
return resp | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,81 @@ | ||
package database | ||
|
||
import ( | ||
"database/sql" | ||
"errors" | ||
|
||
"github.com/turt2live/matrix-media-repo/common/rcontext" | ||
) | ||
|
||
type RestrictedCondition string | ||
|
||
const RestrictedToEvent RestrictedCondition = "event_id" // MSC3911 | ||
const RestrictedToProfile RestrictedCondition = "profile_user_id" // MSC3911 | ||
const RestrictedToUser RestrictedCondition = "io.t2bot.user_id" // Internal extension | ||
|
||
type DbRestrictedMedia struct { | ||
Origin string | ||
MediaId string | ||
Condition RestrictedCondition | ||
ConditionValue string | ||
} | ||
|
||
const insertRestrictedMedia = "INSERT INTO restricted_media (origin, media_id, condition_type, condition_value) VALUES ($1, $2, $3, $4);" | ||
const updateRestrictedMedia = "UPDATE restricted_media SET condition_type = $3, condition_value = $4 WHERE origin = $1 AND media_id = $2;" | ||
const selectRestrictedMedia = "SELECT origin, media_id, condition_type, condition_value FROM restricted_media WHERE origin = $1 AND media_id = $2 LIMIT 1;" | ||
|
||
type restrictedMediaTableStatements struct { | ||
insertRestrictedMedia *sql.Stmt | ||
updateRestrictedMedia *sql.Stmt | ||
selectRestrictedMedia *sql.Stmt | ||
} | ||
|
||
type restrictedMediaTableWithContext struct { | ||
statements *restrictedMediaTableStatements | ||
ctx rcontext.RequestContext | ||
} | ||
|
||
func prepareRestrictedMediaTables(db *sql.DB) (*restrictedMediaTableStatements, error) { | ||
var err error | ||
var stmts = &restrictedMediaTableStatements{} | ||
|
||
if stmts.insertRestrictedMedia, err = db.Prepare(insertRestrictedMedia); err != nil { | ||
return nil, errors.New("error preparing insertRestrictedMedia: " + err.Error()) | ||
} | ||
if stmts.updateRestrictedMedia, err = db.Prepare(updateRestrictedMedia); err != nil { | ||
return nil, errors.New("error preparing updateRestrictedMedia: " + err.Error()) | ||
} | ||
if stmts.selectRestrictedMedia, err = db.Prepare(selectRestrictedMedia); err != nil { | ||
return nil, errors.New("error preparing selectRestrictedMedia: " + err.Error()) | ||
} | ||
|
||
return stmts, nil | ||
} | ||
|
||
func (s *restrictedMediaTableStatements) Prepare(ctx rcontext.RequestContext) *restrictedMediaTableWithContext { | ||
return &restrictedMediaTableWithContext{ | ||
statements: s, | ||
ctx: ctx, | ||
} | ||
} | ||
|
||
func (s *restrictedMediaTableWithContext) Insert(origin string, mediaId string, condition RestrictedCondition, conditionValue string) error { | ||
_, err := s.statements.insertRestrictedMedia.ExecContext(s.ctx, origin, mediaId, condition, conditionValue) | ||
return err | ||
} | ||
|
||
func (s *restrictedMediaTableWithContext) Update(origin string, mediaId string, condition RestrictedCondition, conditionValue string) error { | ||
_, err := s.statements.updateRestrictedMedia.ExecContext(s.ctx, origin, mediaId, condition, conditionValue) | ||
return err | ||
} | ||
|
||
func (s *restrictedMediaTableWithContext) GetById(origin string, mediaId string) (*DbRestrictedMedia, error) { | ||
row := s.statements.selectRestrictedMedia.QueryRowContext(s.ctx, origin, mediaId) | ||
val := &DbRestrictedMedia{} | ||
err := row.Scan(&val.Origin, &val.MediaId, &val.Condition, &val.ConditionValue) | ||
if errors.Is(err, sql.ErrNoRows) { | ||
err = nil | ||
val = nil | ||
} | ||
return val, err | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,2 @@ | ||
DROP INDEX IF EXISTS idx_restricted_media; | ||
DROP TABLE IF EXISTS restricted_media; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,2 @@ | ||
CREATE TABLE IF NOT EXISTS restricted_media (origin TEXT NOT NULL, media_id TEXT NOT NULL, condition_type TEXT NOT NULL, condition_value TEXT NOT NULL); | ||
CREATE UNIQUE INDEX IF NOT EXISTS idx_restricted_media ON restricted_media (origin, media_id); |