diff --git a/lib.go b/lib.go deleted file mode 100644 index d2c590b..0000000 --- a/lib.go +++ /dev/null @@ -1,303 +0,0 @@ -package noteslib - -import ( - "bytes" - "crypto/aes" - "crypto/cipher" - "crypto/pbkdf2" - "crypto/rand" - "crypto/sha256" - "database/sql" - "encoding/base64" - "encoding/json" - "fmt" - "io" - "net/http" - "net/url" - "strconv" - "strings" - "sync" - "time" - - _ "modernc.org/sqlite" -) - -type Note struct { - Body string `json:"body"` - Color int64 `json:"color"` - Date string `json:"date"` - ID string `json:"id"` - Title string `json:"title"` -} - -func decodeColorInt(color int64) (r int64, g int64, b int64, a int64) { - // https://developer.android.com/reference/android/graphics/Color#color-ints - if color == 0 { - return 255, 255, 255, 255 - } - a = (color >> 24) & 0xff // or color >>> 24 - r = (color >> 16) & 0xff - g = (color >> 8) & 0xff - b = (color) & 0xff - return -} - -func encodeToColorInt(r int64, g int64, b int64, a int64) int64 { - // https://developer.android.com/reference/android/graphics/Color#color-ints - return (a&0xff)<<24 | (r&0xff)<<16 | (g&0xff)<<8 | (b & 0xff) -} - -func fetch(serverAddress string, username string) (jsonBody [][2]string, err error) { - response, err := http.Get( - fmt.Sprintf("https://%s/get?user=%s", - serverAddress, - url.QueryEscape(username)), - ) - if err != nil { - return - } - defer response.Body.Close() - - responseBody, err := io.ReadAll(response.Body) - if err != nil { - return - } - - err = json.Unmarshal(responseBody, &jsonBody) - if err != nil { - return - } - - return -} - -func load(db *sql.DB) (notes [][2]string, err error) { - var rowCount int - err = db.QueryRow("SELECT COUNT(*) FROM notes").Scan(&rowCount) - if err != nil { - return - } - - const limit = 100 - if rowCount > limit { // change this if there's ever an option to increase limit - rowCount = limit // change this if there's ever an option to increase limit - } - - rows, err := db.Query("SELECT * FROM notes LIMIT ?", rowCount) - if err != nil { - return - } - defer rows.Close() - - notes = make([][2]string, rowCount) - - for i := 0; rows.Next(); i++ { - var currentRow [2]string - if err != nil { - return - } - notes[i] = currentRow - } - - return -} - -func list(password string, jsonBody [2]string, notes *[]Note, wg *sync.WaitGroup) (err error) { - defer wg.Done() - - decryptedData, err := decrypt(jsonBody[1], password) - if err != nil { - return - } - - var decryptedBody Note - err = json.Unmarshal(decryptedData, &decryptedBody) - if err != nil { - return - } - - decryptedBody.ID = jsonBody[0] - if len(decryptedBody.Title) > 0 && len(decryptedBody.Body) > 0 { - *notes = append(*notes, decryptedBody) // ew - return - } - - return -} - -func del(serverAddress string, username string, uuid string, db *sql.DB) (err error) { - response, err := http.Get(fmt.Sprintf("https://%s/remove?user=%s&id=%s", serverAddress, url.QueryEscape(username), uuid)) - if err != nil { - return - } - defer response.Body.Close() - - _, err = io.ReadAll(response.Body) - if err != nil { - return - } - - stmt, err := db.Prepare("DELETE FROM notes WHERE id=?") - if err != nil { - return - } - defer stmt.Close() - - _, err = stmt.Exec(uuid) - return -} - -func create(title string, body string, newColor string, serverAddress string, username string, password string, templateNote Note) (err error) { - aInt, err := strconv.ParseInt(newColor[0:2], 16, 64) - if err != nil { - return - } - - rInt, err := strconv.ParseInt(newColor[2:4], 16, 64) - if err != nil { - return - } - - gInt, err := strconv.ParseInt(newColor[4:6], 16, 64) - if err != nil { - return - } - - bInt, err := strconv.ParseInt(newColor[6:8], 16, 64) - if err != nil { - return - } - - note := Note{ - Title: title, - Body: strings.ReplaceAll(body, "/", "\n"), - Color: encodeToColorInt(rInt, gInt, bInt, aInt), - Date: strconv.FormatInt(time.Now().UnixMilli(), 10), - } - jsonNote, err := json.Marshal(note) - if err != nil { - return - } - - data, err := encrypt(jsonNote, password) - if err != nil { - return - } - - response, err := http.Get( - fmt.Sprintf( - "https://%s/new?user=%s&data=%s", - serverAddress, url.QueryEscape(username), - url.QueryEscape(data), - ), - ) - if err != nil { - return - } - - defer response.Body.Close() - _, err = io.ReadAll(response.Body) - return -} - -func deriveKey(password string, salt []byte) (block cipher.Block, err error) { - key, err := pbkdf2.Key(sha256.New, password, salt, 65536, 32) - if err != nil { - return - } - - block, err = aes.NewCipher(key) - return -} - -func decrypt(data string, password string) (strippedPlaintext []byte, err error) { - dataBytes, err := base64.StdEncoding.DecodeString(data) - if err != nil { - return - } - - dataBytesLength := len(dataBytes) - if dataBytesLength < 32 { - err = fmt.Errorf("Data is of length %d, 32 required.", dataBytesLength) - return - } - - iv := dataBytes[0:16] - salt := dataBytes[16:32] - ciphertext := dataBytes[32:] - - ciphertextLength := len(ciphertext) - if ciphertextLength%aes.BlockSize != 0 { - err = fmt.Errorf("Ciphertext length %d is not a multiple of block size %d\n", ciphertextLength, aes.BlockSize) - return - } - - plaintext := make([]byte, ciphertextLength) - block, err := deriveKey(password, salt) - if err != nil { - return - } - - mode := cipher.NewCBCDecrypter(block, iv) - mode.CryptBlocks(plaintext, ciphertext) - - strippedPlaintext, err = unpad(plaintext, 16) - return -} - -func encrypt(data []byte, password string) (encrypted string, err error) { - salt := make([]byte, 16) - iv := make([]byte, 16) - rand.Read(salt) - rand.Read(iv) - - plaintext, err := pad(data, 16) - if err != nil { - return - } - - block, err := deriveKey(password, salt) - if err != nil { - return - } - - mode := cipher.NewCBCEncrypter(block, iv) - ciphertext := make([]byte, len(plaintext)) - mode.CryptBlocks(ciphertext, plaintext) - - encrypted = base64.StdEncoding.EncodeToString( - bytes.Join( - [][]byte{ - iv, - salt, - ciphertext, - }, - []byte(""), - ), - ) - return -} - -func pad(buf []byte, size int) ([]byte, error) { - // https://github.com/mergermarket/go-pkcs7/blob/master/pkcs7.go - bufLen := len(buf) - padLen := size - bufLen%size - padded := make([]byte, bufLen+padLen) - copy(padded, buf) - for i := range padLen { - padded[bufLen+i] = byte(padLen) - } - return padded, nil -} - -func unpad(padded []byte, size int) (buf []byte, err error) { - if len(padded)%size != 0 { - err = fmt.Errorf("Padded value wasn't in correct size for pkcs7") - return - } - - bufLen := len(padded) - int(padded[len(padded)-1]) - buf = make([]byte, bufLen) - copy(buf, padded[:bufLen]) - return -}