Skip to content

Commit

Permalink
update decrypt
Browse files Browse the repository at this point in the history
  • Loading branch information
sayem314 committed Sep 26, 2024
1 parent e9fd50a commit f493584
Show file tree
Hide file tree
Showing 7 changed files with 137 additions and 15 deletions.
Binary file modified .DS_Store
Binary file not shown.
1 change: 1 addition & 0 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ require (
github.com/dgraph-io/badger/v4 v4.3.0
github.com/go-resty/resty/v2 v2.15.2
github.com/stretchr/testify v1.9.0
golang.org/x/crypto v0.27.0
)

require (
Expand Down
2 changes: 2 additions & 0 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,8 @@ go.opencensus.io v0.24.0/go.mod h1:vNK8G9p7aAivkbmorf4v+7Hgx+Zs0yY+0fOtgBfjQKo=
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
golang.org/x/crypto v0.27.0 h1:GXm2NjJrPaiv/h1tb2UH8QfgC/hOf/+z0p6PT8o1w7A=
golang.org/x/crypto v0.27.0/go.mod h1:1Xngt8kV6Dvbssa53Ziq6Eqn0HqbZi5Z6R0ZpwQzt70=
golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU=
Expand Down
45 changes: 33 additions & 12 deletions pkg/decrypt/decrypt.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,12 @@ package decrypt

import (
"crypto/aes"
"crypto/cipher"
"crypto/md5"
"encoding/hex"
"fmt"

"golang.org/x/crypto/blowfish"
)

type TrackType struct {
Expand All @@ -19,23 +22,41 @@ func Md5Hash(data string) string {
}

func GetSongFileName(track *TrackType, quality int) string {
// Step 1: Combine track details into a specific format
step1 := fmt.Sprintf("%s¤%d¤%s¤%s", track.MD5_ORIGIN, quality, track.SNG_ID, track.MEDIA_VERSION)

// Step 2: Generate MD5 hash and concatenate it with step1, ensuring it's a multiple of 16 bytes
step2 := Md5Hash(step1) + "¤" + step1 + "¤"
for len(step2)%16 > 0 {
step2 += " "
}

// AES-128-ECB encryption
cipherKey := []byte("jo6aey6haid2Teih")
block, err := aes.NewCipher(cipherKey)
if err != nil {
panic(err)
}

cipherText := make([]byte, len(step2))
block.Encrypt(cipherText, []byte(step2))
// Encrypt in ECB mode manually since Go's AES doesn't support ECB directly
encrypted := make([]byte, len(step2))
encryptECB(block, []byte(step2), encrypted)

return hex.EncodeToString(cipherText)
return hex.EncodeToString(encrypted)
}

// ECB mode encryption helper function since Go's crypto library doesn't directly support ECB.
func encryptECB(block cipher.Block, src, dst []byte) {
bs := block.BlockSize()
if len(src)%bs != 0 {
panic("plaintext is not a multiple of the block size")
}

for len(src) > 0 {
block.Encrypt(dst, src[:bs])
src = src[bs:]
dst = dst[bs:]
}
}

func GetBlowfishKey(trackID string) string {
Expand All @@ -49,15 +70,16 @@ func GetBlowfishKey(trackID string) string {
}

func DecryptChunk(chunk []byte, blowfishKey string) []byte {
block, err := aes.NewCipher([]byte(blowfishKey))
iv := []byte{0, 1, 2, 3, 4, 5, 6, 7}
block, err := blowfish.NewCipher([]byte(blowfishKey))
if err != nil {
panic(err)
}

cipherText := make([]byte, len(chunk))
block.Decrypt(cipherText, chunk)

return cipherText
dst := make([]byte, len(chunk))
mode := cipher.NewCBCDecrypter(block, iv)
mode.CryptBlocks(dst, chunk)
return dst
}

func DecryptDownload(source []byte, trackID string) []byte {
Expand All @@ -81,14 +103,13 @@ func DecryptDownload(source []byte, trackID string) []byte {
chunk := make([]byte, chunkSize)
copy(chunk, source[position:position+chunkSize])

var chunkString string
if i%3 > 0 || chunkSize < 2048 {
chunkString = string(chunk)
copy(destBuffer[position:], chunk)
} else {
chunkString = string(DecryptChunk(chunk, blowfishKey))
decryptedChunk := DecryptChunk(chunk, blowfishKey)
copy(destBuffer[position:], decryptedChunk)
}

copy(destBuffer[position:position+len(chunkString)], chunkString)
position += chunkSize
i++
}
Expand Down
88 changes: 88 additions & 0 deletions pkg/download/download.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
package download

import (
"fmt"
"os"
"path/filepath"
"strings"
"time"

"github.com/d-fi/GoFi/pkg/api"
"github.com/d-fi/GoFi/pkg/decrypt"
"github.com/d-fi/GoFi/pkg/types"
"github.com/go-resty/resty/v2"
)

var client = resty.New()

// Path to save music, update this to match your configuration
var MusicPath = "./music" // Change this to the desired path for storing music files

// DownloadTrack downloads a track, adds metadata, and saves it to disk.
func DownloadTrack(sngID string, quality int, ext string, coverSize int) (string, error) {
// Fetch track information
track, err := api.GetTrackInfo(sngID)
if err != nil {
return "", fmt.Errorf("failed to fetch track info: %v", err)
}

// Create directory if it does not exist
qualityPath := filepath.Join(MusicPath, fmt.Sprintf("%d", quality))
if _, err := os.Stat(qualityPath); os.IsNotExist(err) {
if err := os.MkdirAll(qualityPath, 0755); err != nil {
return "", fmt.Errorf("failed to create directory: %v", err)
}
}

// Get the track download URL
trackData, err := GetTrackDownloadUrl(track, quality)
if err != nil || trackData == nil {
return "", fmt.Errorf("failed to retrieve downloadable URL: %v", err)
}

// Set up the save path for the track
safeTitle := strings.ReplaceAll(track.SNG_TITLE, "/", "_")
savedPath := filepath.Join(qualityPath, fmt.Sprintf("%s-%s.%s", safeTitle, track.SNG_ID, ext))

// Check if the file exists and update its timestamp if it does
if _, err := os.Stat(savedPath); err == nil {
currentTime := time.Now().Local()
if err := os.Chtimes(savedPath, currentTime, currentTime); err != nil {
return "", fmt.Errorf("failed to update file timestamps: %v", err)
}
} else {
// Download the track
resp, err := client.R().Get(trackData.TrackUrl)
if err != nil {
return "", fmt.Errorf("failed to download track: %v", err)
}

// Check if decryption is needed and add metadata
var trackBody []byte
if trackData.IsEncrypted {
trackBody = decrypt.DecryptDownload(resp.Body(), track.SNG_ID)
} else {
trackBody = resp.Body()
}

// Add metadata to the track
trackWithMetadata, err := addTrackTags(trackBody, track, coverSize)
if err != nil {
return "", fmt.Errorf("failed to add metadata: %v", err)
}

// Write the track to disk
if err := os.WriteFile(savedPath, trackWithMetadata, 0644); err != nil {
return "", fmt.Errorf("failed to save track: %v", err)
}
}

return savedPath, nil
}

// addTrackTags adds metadata to the track. Implement this function based on your metadata requirements.
func addTrackTags(body []byte, track types.TrackType, coverSize int) ([]byte, error) {
// Add track metadata handling code here
// This is a placeholder implementation. Replace with actual metadata tagging logic.
return body, nil
}
13 changes: 11 additions & 2 deletions pkg/request/request.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,17 @@ func checkResponse(data []byte) (json.RawMessage, error) {
return nil, fmt.Errorf("failed to unmarshal API response: %v", err)
}

if len(apiResponse.Error) > 0 {
return nil, fmt.Errorf("API error: %v", apiResponse.Error)
// Check if the response contains error data in different formats
switch errVal := apiResponse.Error.(type) {
case string:
return nil, fmt.Errorf("API error: %s", errVal)
case map[string]interface{}:
// Convert the map to a string for better error message readability
errorMessage := ""
for key, value := range errVal {
errorMessage += fmt.Sprintf("%s: %v, ", key, value)
}
return nil, fmt.Errorf("API error: %v", errorMessage)
}

return apiResponse.Results, nil
Expand Down
3 changes: 2 additions & 1 deletion pkg/request/types.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,9 @@ package request
import "encoding/json"

type APIResponse struct {
Error []string `json:"error"`
Error interface{} `json:"error"`
Results json.RawMessage `json:"results"`
Payload interface{} `json:"payload,omitempty"`
}

type PublicAPIResponseError struct {
Expand Down

0 comments on commit f493584

Please sign in to comment.