✨ Encrypted channels
This commit is contained in:
		@@ -19,6 +19,7 @@ type Channel struct {
 | 
				
			|||||||
	Type        ChannelType     `json:"type"`
 | 
						Type        ChannelType     `json:"type"`
 | 
				
			||||||
	Account     Account         `json:"account"`
 | 
						Account     Account         `json:"account"`
 | 
				
			||||||
	AccountID   uint            `json:"account_id"`
 | 
						AccountID   uint            `json:"account_id"`
 | 
				
			||||||
 | 
						IsEncrypted bool            `json:"is_encrypted"`
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	Realm   Realm `json:"realm"`
 | 
						Realm   Realm `json:"realm"`
 | 
				
			||||||
	RealmID *uint `json:"realm_id"`
 | 
						RealmID *uint `json:"realm_id"`
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,18 +1,15 @@
 | 
				
			|||||||
package models
 | 
					package models
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import "gorm.io/datatypes"
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
type Message struct {
 | 
					type Message struct {
 | 
				
			||||||
	BaseModel
 | 
						BaseModel
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	Content     []byte            `json:"content"`
 | 
						Content     []byte        `json:"content"`
 | 
				
			||||||
	Metadata    datatypes.JSONMap `json:"metadata"`
 | 
						Type        string        `json:"type"`
 | 
				
			||||||
	Type        string            `json:"type"`
 | 
						Attachments []Attachment  `json:"attachments"`
 | 
				
			||||||
	Attachments []Attachment      `json:"attachments"`
 | 
						Channel     Channel       `json:"channel"`
 | 
				
			||||||
	Channel     Channel           `json:"channel"`
 | 
						Sender      ChannelMember `json:"sender"`
 | 
				
			||||||
	Sender      ChannelMember     `json:"sender"`
 | 
						ReplyID     *uint         `json:"reply_id"`
 | 
				
			||||||
	ReplyID     *uint             `json:"reply_id"`
 | 
						ReplyTo     *Message      `json:"reply_to" gorm:"foreignKey:ReplyID"`
 | 
				
			||||||
	ReplyTo     *Message          `json:"reply_to" gorm:"foreignKey:ReplyID"`
 | 
						ChannelID   uint          `json:"channel_id"`
 | 
				
			||||||
	ChannelID   uint              `json:"channel_id"`
 | 
						SenderID    uint          `json:"sender_id"`
 | 
				
			||||||
	SenderID    uint              `json:"sender_id"`
 | 
					 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -99,6 +99,7 @@ func createChannel(c *fiber.Ctx) error {
 | 
				
			|||||||
		Alias       string `json:"alias" validate:"required,lowercase,min=4,max=32"`
 | 
							Alias       string `json:"alias" validate:"required,lowercase,min=4,max=32"`
 | 
				
			||||||
		Name        string `json:"name" validate:"required"`
 | 
							Name        string `json:"name" validate:"required"`
 | 
				
			||||||
		Description string `json:"description"`
 | 
							Description string `json:"description"`
 | 
				
			||||||
 | 
							IsEncrypted bool   `json:"is_encrypted"`
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if err := BindAndValidate(c, &data); err != nil {
 | 
						if err := BindAndValidate(c, &data); err != nil {
 | 
				
			||||||
@@ -121,9 +122,9 @@ func createChannel(c *fiber.Ctx) error {
 | 
				
			|||||||
	var err error
 | 
						var err error
 | 
				
			||||||
	var channel models.Channel
 | 
						var channel models.Channel
 | 
				
			||||||
	if realm != nil {
 | 
						if realm != nil {
 | 
				
			||||||
		channel, err = services.NewChannel(user, data.Alias, data.Name, data.Description, realm.ID)
 | 
							channel, err = services.NewChannel(user, data.Alias, data.Name, data.Description, data.IsEncrypted, realm.ID)
 | 
				
			||||||
	} else {
 | 
						} else {
 | 
				
			||||||
		channel, err = services.NewChannel(user, data.Alias, data.Name, data.Description)
 | 
							channel, err = services.NewChannel(user, data.Alias, data.Name, data.Description, data.IsEncrypted)
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if err != nil {
 | 
						if err != nil {
 | 
				
			||||||
@@ -141,6 +142,7 @@ func editChannel(c *fiber.Ctx) error {
 | 
				
			|||||||
		Alias       string `json:"alias" validate:"required,min=4,max=32"`
 | 
							Alias       string `json:"alias" validate:"required,min=4,max=32"`
 | 
				
			||||||
		Name        string `json:"name" validate:"required"`
 | 
							Name        string `json:"name" validate:"required"`
 | 
				
			||||||
		Description string `json:"description"`
 | 
							Description string `json:"description"`
 | 
				
			||||||
 | 
							IsEncrypted bool   `json:"is_encrypted"`
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if err := BindAndValidate(c, &data); err != nil {
 | 
						if err := BindAndValidate(c, &data); err != nil {
 | 
				
			||||||
@@ -166,7 +168,7 @@ func editChannel(c *fiber.Ctx) error {
 | 
				
			|||||||
		return fiber.NewError(fiber.StatusNotFound, err.Error())
 | 
							return fiber.NewError(fiber.StatusNotFound, err.Error())
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	channel, err := services.EditChannel(channel, data.Alias, data.Name, data.Description)
 | 
						channel, err := services.EditChannel(channel, data.Alias, data.Name, data.Description, data.IsEncrypted)
 | 
				
			||||||
	if err != nil {
 | 
						if err != nil {
 | 
				
			||||||
		return fiber.NewError(fiber.StatusBadRequest, err.Error())
 | 
							return fiber.NewError(fiber.StatusBadRequest, err.Error())
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,7 +1,6 @@
 | 
				
			|||||||
package server
 | 
					package server
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import (
 | 
					import (
 | 
				
			||||||
	"encoding/base64"
 | 
					 | 
				
			||||||
	"encoding/json"
 | 
						"encoding/json"
 | 
				
			||||||
	"fmt"
 | 
						"fmt"
 | 
				
			||||||
	"git.solsynth.dev/hydrogen/messaging/pkg/database"
 | 
						"git.solsynth.dev/hydrogen/messaging/pkg/database"
 | 
				
			||||||
@@ -48,7 +47,6 @@ func newMessage(c *fiber.Ctx) error {
 | 
				
			|||||||
	var data struct {
 | 
						var data struct {
 | 
				
			||||||
		Type        string              `json:"type" validate:"required"`
 | 
							Type        string              `json:"type" validate:"required"`
 | 
				
			||||||
		Content     map[string]any      `json:"content"`
 | 
							Content     map[string]any      `json:"content"`
 | 
				
			||||||
		Metadata    map[string]any      `json:"metadata"`
 | 
					 | 
				
			||||||
		Attachments []models.Attachment `json:"attachments"`
 | 
							Attachments []models.Attachment `json:"attachments"`
 | 
				
			||||||
		ReplyTo     *uint               `json:"reply_to"`
 | 
							ReplyTo     *uint               `json:"reply_to"`
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
@@ -74,22 +72,17 @@ func newMessage(c *fiber.Ctx) error {
 | 
				
			|||||||
		}
 | 
							}
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	var encodedContent []byte
 | 
						rawContent, err := json.Marshal(data.Content)
 | 
				
			||||||
	if raw, err := json.Marshal(data.Content); err != nil {
 | 
						if err != nil {
 | 
				
			||||||
		return fiber.NewError(fiber.StatusBadRequest, fmt.Sprintf("invalid message content, unable to encode: %v", err))
 | 
							return fiber.NewError(fiber.StatusBadRequest, fmt.Sprintf("invalid message content, unable to encode: %v", err))
 | 
				
			||||||
	} else {
 | 
					 | 
				
			||||||
		encoder := base64.StdEncoding
 | 
					 | 
				
			||||||
		encodedContent = make([]byte, encoder.EncodedLen(len(raw)))
 | 
					 | 
				
			||||||
		encoder.Encode(encodedContent, raw)
 | 
					 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	message := models.Message{
 | 
						message := models.Message{
 | 
				
			||||||
		Content:     encodedContent,
 | 
							Content:     rawContent,
 | 
				
			||||||
		Sender:      member,
 | 
							Sender:      member,
 | 
				
			||||||
		Channel:     channel,
 | 
							Channel:     channel,
 | 
				
			||||||
		ChannelID:   channel.ID,
 | 
							ChannelID:   channel.ID,
 | 
				
			||||||
		SenderID:    member.ID,
 | 
							SenderID:    member.ID,
 | 
				
			||||||
		Metadata:    data.Metadata,
 | 
					 | 
				
			||||||
		Attachments: data.Attachments,
 | 
							Attachments: data.Attachments,
 | 
				
			||||||
		Type:        data.Type,
 | 
							Type:        data.Type,
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
@@ -119,7 +112,6 @@ func editMessage(c *fiber.Ctx) error {
 | 
				
			|||||||
	var data struct {
 | 
						var data struct {
 | 
				
			||||||
		Type        string              `json:"type" validate:"required"`
 | 
							Type        string              `json:"type" validate:"required"`
 | 
				
			||||||
		Content     map[string]any      `json:"content"`
 | 
							Content     map[string]any      `json:"content"`
 | 
				
			||||||
		Metadata    map[string]any      `json:"metadata"`
 | 
					 | 
				
			||||||
		Attachments []models.Attachment `json:"attachments"`
 | 
							Attachments []models.Attachment `json:"attachments"`
 | 
				
			||||||
		ReplyTo     *uint               `json:"reply_to"`
 | 
							ReplyTo     *uint               `json:"reply_to"`
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
@@ -148,18 +140,13 @@ func editMessage(c *fiber.Ctx) error {
 | 
				
			|||||||
		return fiber.NewError(fiber.StatusNotFound, err.Error())
 | 
							return fiber.NewError(fiber.StatusNotFound, err.Error())
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	var encodedContent []byte
 | 
						rawContent, err := json.Marshal(data.Content)
 | 
				
			||||||
	if raw, err := json.Marshal(data.Content); err != nil {
 | 
						if err != nil {
 | 
				
			||||||
		return fiber.NewError(fiber.StatusBadRequest, fmt.Sprintf("invalid message content, unable to encode: %v", err))
 | 
							return fiber.NewError(fiber.StatusBadRequest, fmt.Sprintf("invalid message content, unable to encode: %v", err))
 | 
				
			||||||
	} else {
 | 
					 | 
				
			||||||
		encoder := base64.StdEncoding
 | 
					 | 
				
			||||||
		encodedContent = make([]byte, encoder.EncodedLen(len(raw)))
 | 
					 | 
				
			||||||
		encoder.Encode(encodedContent, raw)
 | 
					 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	message.Attachments = data.Attachments
 | 
						message.Attachments = data.Attachments
 | 
				
			||||||
	message.Metadata = data.Metadata
 | 
						message.Content = rawContent
 | 
				
			||||||
	message.Content = encodedContent
 | 
					 | 
				
			||||||
	message.Type = data.Type
 | 
						message.Type = data.Type
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	message, err = services.EditMessage(message)
 | 
						message, err = services.EditMessage(message)
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -134,11 +134,12 @@ func ListAvailableChannel(user models.Account, realmId ...uint) ([]models.Channe
 | 
				
			|||||||
	return channels, nil
 | 
						return channels, nil
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func NewChannel(user models.Account, alias, name, description string, realmId ...uint) (models.Channel, error) {
 | 
					func NewChannel(user models.Account, alias, name, description string, isEncrypted bool, realmId ...uint) (models.Channel, error) {
 | 
				
			||||||
	channel := models.Channel{
 | 
						channel := models.Channel{
 | 
				
			||||||
		Alias:       alias,
 | 
							Alias:       alias,
 | 
				
			||||||
		Name:        name,
 | 
							Name:        name,
 | 
				
			||||||
		Description: description,
 | 
							Description: description,
 | 
				
			||||||
 | 
							IsEncrypted: isEncrypted,
 | 
				
			||||||
		AccountID:   user.ID,
 | 
							AccountID:   user.ID,
 | 
				
			||||||
		Members: []models.ChannelMember{
 | 
							Members: []models.ChannelMember{
 | 
				
			||||||
			{AccountID: user.ID},
 | 
								{AccountID: user.ID},
 | 
				
			||||||
@@ -153,10 +154,13 @@ func NewChannel(user models.Account, alias, name, description string, realmId ..
 | 
				
			|||||||
	return channel, err
 | 
						return channel, err
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func EditChannel(channel models.Channel, alias, name, description string) (models.Channel, error) {
 | 
					func EditChannel(channel models.Channel, alias, name, description string, isEncrypted bool) (models.Channel, error) {
 | 
				
			||||||
	channel.Alias = alias
 | 
						channel.Alias = alias
 | 
				
			||||||
	channel.Name = name
 | 
						channel.Name = name
 | 
				
			||||||
	channel.Description = description
 | 
						channel.Description = description
 | 
				
			||||||
 | 
						if !channel.IsEncrypted {
 | 
				
			||||||
 | 
							channel.IsEncrypted = isEncrypted
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	err := database.C.Save(&channel).Error
 | 
						err := database.C.Save(&channel).Error
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
		Reference in New Issue
	
	Block a user