github.com/Azareal/Gosora@v0.0.0-20210729070923-553e66b59003/common/convos_posts.go (about)

     1  package common
     2  
     3  import (
     4  	"crypto/aes"
     5  	"crypto/cipher"
     6  	"crypto/rand"
     7  	"encoding/hex"
     8  	"io"
     9  )
    10  
    11  var ConvoPostProcess ConvoPostProcessor = NewDefaultConvoPostProcessor()
    12  
    13  type ConvoPostProcessor interface {
    14  	OnLoad(co *ConversationPost) (*ConversationPost, error)
    15  	OnSave(co *ConversationPost) (*ConversationPost, error)
    16  }
    17  
    18  type DefaultConvoPostProcessor struct {
    19  }
    20  
    21  func NewDefaultConvoPostProcessor() *DefaultConvoPostProcessor {
    22  	return &DefaultConvoPostProcessor{}
    23  }
    24  
    25  func (pr *DefaultConvoPostProcessor) OnLoad(co *ConversationPost) (*ConversationPost, error) {
    26  	return co, nil
    27  }
    28  
    29  func (pr *DefaultConvoPostProcessor) OnSave(co *ConversationPost) (*ConversationPost, error) {
    30  	return co, nil
    31  }
    32  
    33  type AesConvoPostProcessor struct {
    34  }
    35  
    36  func NewAesConvoPostProcessor() *AesConvoPostProcessor {
    37  	return &AesConvoPostProcessor{}
    38  }
    39  
    40  func (pr *AesConvoPostProcessor) OnLoad(co *ConversationPost) (*ConversationPost, error) {
    41  	if co.Post != "aes" {
    42  		return co, nil
    43  	}
    44  	key, _ := hex.DecodeString(Config.ConvoKey)
    45  
    46  	ciphertext, err := hex.DecodeString(co.Body)
    47  	if err != nil {
    48  		return nil, err
    49  	}
    50  
    51  	block, err := aes.NewCipher(key)
    52  	if err != nil {
    53  		return nil, err
    54  	}
    55  
    56  	aesgcm, err := cipher.NewGCM(block)
    57  	if err != nil {
    58  		return nil, err
    59  	}
    60  
    61  	nonceSize := aesgcm.NonceSize()
    62  	if len(ciphertext) < nonceSize {
    63  		return nil, err
    64  	}
    65  
    66  	nonce, ciphertext := ciphertext[:nonceSize], ciphertext[nonceSize:]
    67  	plaintext, err := aesgcm.Open(nil, nonce, ciphertext, nil)
    68  	if err != nil {
    69  		return nil, err
    70  	}
    71  
    72  	lco := *co
    73  	lco.Body = string(plaintext)
    74  	return &lco, nil
    75  }
    76  
    77  func (pr *AesConvoPostProcessor) OnSave(co *ConversationPost) (*ConversationPost, error) {
    78  	key, _ := hex.DecodeString(Config.ConvoKey)
    79  	block, err := aes.NewCipher(key)
    80  	if err != nil {
    81  		return nil, err
    82  	}
    83  
    84  	nonce := make([]byte, 12)
    85  	if _, err := io.ReadFull(rand.Reader, nonce); err != nil {
    86  		return nil, err
    87  	}
    88  
    89  	aesgcm, err := cipher.NewGCM(block)
    90  	if err != nil {
    91  		return nil, err
    92  	}
    93  	ciphertext := aesgcm.Seal(nil, nonce, []byte(co.Body), nil)
    94  
    95  	lco := *co
    96  	lco.Body = hex.EncodeToString(ciphertext)
    97  	lco.Post = "aes"
    98  	return &lco, nil
    99  }
   100  
   101  type ConversationPost struct {
   102  	ID        int
   103  	CID       int
   104  	Body      string
   105  	Post      string // aes, ''
   106  	CreatedBy int
   107  }
   108  
   109  // TODO: Should we run OnLoad on this? Or maybe add a FetchMeta method to avoid having to decode the message when it's not necessary?
   110  func (co *ConversationPost) Fetch() error {
   111  	return convoStmts.fetchPost.QueryRow(co.ID).Scan(&co.CID, &co.Body, &co.Post, &co.CreatedBy)
   112  }
   113  
   114  func (co *ConversationPost) Update() error {
   115  	lco, err := ConvoPostProcess.OnSave(co)
   116  	if err != nil {
   117  		return err
   118  	}
   119  	//GetHookTable().VhookNoRet("convo_post_update", lco)
   120  	_, err = convoStmts.editPost.Exec(lco.Body, lco.Post, lco.ID)
   121  	return err
   122  }
   123  
   124  func (co *ConversationPost) Create() (int, error) {
   125  	lco, err := ConvoPostProcess.OnSave(co)
   126  	if err != nil {
   127  		return 0, err
   128  	}
   129  	//GetHookTable().VhookNoRet("convo_post_create", lco)
   130  	res, err := convoStmts.createPost.Exec(lco.CID, lco.Body, lco.Post, lco.CreatedBy)
   131  	if err != nil {
   132  		return 0, err
   133  	}
   134  
   135  	lastID, err := res.LastInsertId()
   136  	return int(lastID), err
   137  }
   138  
   139  func (co *ConversationPost) Delete() error {
   140  	_, err := convoStmts.deletePost.Exec(co.ID)
   141  	return err
   142  }