123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593 |
- package common
- import (
- "crypto/rand"
- "crypto/tls"
- "errors"
- "fmt"
- "io"
- "math"
- "math/big"
- "time"
- "github.com/dgrijalva/jwt-go"
- "github.com/ethereum/go-ethereum/common"
- "github.com/gin-gonic/gin"
- "github.com/metarare/metarare_api/contracts/operator"
- "github.com/metarare/metarare_api/helpers"
- "github.com/metarare/metarare_api/helpers/gauth"
- "github.com/metarare/metarare_api/models"
- "github.com/spf13/viper"
- gomail "gopkg.in/mail.v2"
- "gorm.io/gorm"
- )
- var (
- EMAIL_HOST string = "smtp.mailplug.co.kr"
- EMAIL_PORT int = 465
- EMAIL_SUBJECT string = "Certification Code\n"
- EMAIL_MIME string = "MIME-version: 1.0;\nContent-Type: text/html; charset=\"UTF-8\";\n\n"
- )
- type Email struct {
- From string `json:"from,omitempty"`
- Password string `json:"password,omitempty"`
- ToList string `json:"toList,omitempty"`
- Host string `json:"host,omitempty"`
- Port string `json:"port,omitempty"`
- Subject string `json:"subject,omitempty"`
- Mime string `json:"mime,omitempty"`
- Message string `json:"message,omitempty"`
- }
- type Router struct {
- Engine *gin.Engine
- Port string
- Version *gin.RouterGroup
- Db DataBases
- Env *viper.Viper
- }
- type DataBases struct {
- MasterDB *gorm.DB
- ReadDB *gorm.DB
- }
- type JsonObject map[string]interface{}
- type AuthContainer struct {
- AccessToken string `json:"access_token,omitempty"`
- }
- type SwagStruct struct {
- Json string `json:"json"`
- }
- type FILTER_KEY string
- var Decimal13 = int64(math.Pow(10, 13)) // 10^13
- type MakeHashData struct {
- OwnerAddress string `json:"owner_address"`
- CollectionAddress string `json:"collection_address"`
- TokenType string `json:"token_type"`
- TokenID int64 `json:"token_id"`
- Currency string `json:"currency"`
- Price float64 `json:"price"`
- Index int64 `json:"index"`
- TotalIndex int64 `json:"total_index"`
- CreationTax int64 `json:"creation_tax"`
- TreasuryTax float64 `json:"treasury_tax"`
- TreasuryAddress string `json:"treasury_address"`
- TargetPrivateKey string `json:"target_private_key"`
- PrevTreasuryTax int64 `json:"prev_treasury_tax"`
- }
- const (
- NETWORK_ETH = FILTER_KEY("eth")
- NETWORK_BSC = FILTER_KEY("bsc")
- NETWORK_MR = FILTER_KEY("mr")
- )
- const (
- CATEGORY_ALL = FILTER_KEY("all")
- CATEGORY_ART = FILTER_KEY("art")
- CATEGORY_GAME = FILTER_KEY("game")
- )
- const (
- SALETYPE_FIXED = FILTER_KEY("fixed")
- SALETYPE_BID = FILTER_KEY("bid")
- SALETYPE_TIME = FILTER_KEY("time")
- )
- const (
- CURRENCY_ETH = FILTER_KEY("eth")
- CURRENCY_MR = FILTER_KEY("mr")
- CURRENCY_MF = FILTER_KEY("mf")
- )
- const (
- CURRENCY_AMOUNT_START = FILTER_KEY("currency_amount_strart")
- CURRENCY_AMOUNT_END = FILTER_KEY("currency_amount_end")
- )
- var NETWORKS = []FILTER_KEY{NETWORK_ETH, NETWORK_BSC, NETWORK_MR}
- var CATEGORIES = []FILTER_KEY{CATEGORY_ALL, CATEGORY_ART, CATEGORY_GAME}
- var SALETYPES = []FILTER_KEY{SALETYPE_FIXED, SALETYPE_BID, SALETYPE_TIME}
- var CURRENCIES = []FILTER_KEY{CURRENCY_ETH, CURRENCY_MF, CURRENCY_MR}
- var (
- tt256 = BigPow(2, 256)
- tt256m1 = new(big.Int).Sub(tt256, big.NewInt(1))
- MaxBig256 = new(big.Int).Set(tt256m1)
- )
- type Filter struct {
- Network string `json:"network,omitempty"`
- Category string `json:"category,omitempty"`
- CollectionName string `json:"collection_name,omitempty"`
- SaleType string `json:"sale_type,omitempty"`
- Currency string `json:"currency,omitempty"`
- CurrencyAmountStart string `json:"currency_amount_start,omitempty"`
- CurrencyAmountEnd string `json:"currency_amount_end,omitempty"`
- SaleStatus string `json:"sale_status,omitempty"` // for 개인페이지의 판매중
- Offset int `json:"offset,omitempty" default:"-1"`
- Limit int `json:"limit,omitempty" default:"-1"`
- TokenName string `json:"token_name,omitempty"`
- }
- type ExpItem struct { // exploreItem
- CollectionID uint64 `json:"collection_id"`
- CollectionThumbnailImage string `json:"collection_thumbnail_image"`
- CollectionName string `json:"collection_name"`
- IsOfficialCollection bool `json:"is_official_collection"`
- UserID uint64 `json:"user_id"`
- IsArtist bool `json:"is_artist"`
- OwnerThumbnailImage string `json:"owner_thumbnail_image"`
- OwnerName string `json:"owner_name"`
- TokenID uint64 `json:"token_id"`
- ContentURL string `json:"content_url"`
- ContentTitle string `json:"content_title"`
- LastestPrice string `json:"lastest_price"`
- LastestCurrency string `json:"lastest_currency"`
- ItemIndex int `json:"item_index"`
- TotalCount int `json:"total_count"`
- SaleID uint64 `json:"sale_id"`
- SaleType string `json:"sale_type"`
- SaleStatus string `json:"sale_status"`
- FixedPrice string `json:"fixed_price"`
- CurrentCurrency string `json:"current_currency"`
- CurrentPrice string `json:"current_price"`
- BidCount int `json:"bid_count"`
- Likes int `json:"likes"`
- IsLike bool `json:"is_like"`
- StartPrice string `json:"start_price"`
- EndAt time.Time `json:"end_at"`
- CreatedAt time.Time `json:"created_at"`
- }
- type CollectionItem struct {
- CollectionID uint64 `json:"collection_id"`
- CoverImage string `json:"cover_image"`
- ThumbnailImage string `json:"thumbnail_image"`
- IsOfficial bool `json:"is_official"`
- CollectionName string `json:"collection_name"`
- UserID uint64 `json:"user_id"`
- OwnerName string `json:"owner_name"`
- TotalVolume float32 `json:"total_volume"`
- TotalItem int `json:"total_item"`
- }
- type ActivityItem struct {
- LogRelationID uint64 `json:"log_relation_id"`
- TokenContentURL string `json:"token_content_url"`
- TokenName string `json:"token_name"`
- LogType string `json:"log_type"`
- SaleUID string `json:"sale_uid"`
- ToAddress string `json:"to_address"`
- FromAddress string `json:"from_address"`
- Price string `json:"price"`
- Currency string `json:"currency"`
- SaleID uint64 `json:"sale_id"`
- TokenID uint64 `json:"token_id"`
- IsCancel bool `json:"is_cancel"`
- Tx string `json:"tx"`
- CreatedAt time.Time `json:"created_at"`
- FromUserProfile string `json:"from_user_profile"`
- FromUserName string `json:"from_user_name"`
- FromUserIsArtist bool `json:"from_user_is_artist"`
- ToUserProfile string `json:"to_user_profile"`
- ToUserName string `json:"to_user_name"`
- ToUserIsArtist bool `json:"to_user_is_artist"`
- }
- type BidItem struct {
- UserID uint64
- UserThumbnailImage string
- UserName string
- IsCancel string
- ActionType string
- }
- type ArtistItem struct {
- ID uint64
- UserID uint64
- Team string
- Category string
- ThumbnailImage string
- }
- type TopSales struct {
- UserId uint64 `json:"artist_id"`
- ThumbnailImage string `json:"thumbnail_image"`
- CoverImage string `json:"cover_image"`
- Name string `json:"name"`
- Category string `json:"category"`
- AmountSales float64 `json:"amounts_sale"`
- }
- type SearchExpItems struct {
- Result []ExpItem
- Suggestion []CollectionItem
- }
- // SECTION jwt session
- func MakeClaims(userID int64) (JsonObject, JsonObject) {
- standardClaims := JsonObject{
- "iss": "metarare.com",
- "aud": gauth.User,
- }
- customClaims := JsonObject{
- gauth.Pack("user_id"): gauth.Pack(fmt.Sprintf("%d", userID)),
- }
- return standardClaims, customClaims
- }
- func MakeSession(standardClaims JsonObject, customClaims JsonObject) (error, AuthContainer) {
- currentTimestamp := time.Now()
- claims := jwt.MapClaims{}
- claims["sub"] = "access_key"
- claims["iat"] = currentTimestamp.Unix()
- claims["exp"] = currentTimestamp.Add(24 * time.Hour).Format(time.RFC3339)
- for k, v := range standardClaims {
- claims[k] = v
- }
- for k, v := range customClaims {
- claims[k] = v
- }
- token := jwt.NewWithClaims(jwt.SigningMethodHS256, claims)
- tokenString, err := token.SignedString([]byte(gauth.ObtainJWTKey()))
- fmt.Println(tokenString, err)
- return nil, AuthContainer{AccessToken: tokenString}
- }
- func MakeJwtToken(userID uint64) AuthContainer {
- standardClaims, customClaims := MakeClaims(int64(userID))
- _, authContainer := MakeSession(standardClaims, customClaims)
- return authContainer
- }
- // SECTION GenerateRandomHexString
- func GenerateRandomString(max int, prefix string) string {
- var table = [...]byte{'1', '2', '3', '4', '5', '6', '7', '8', '9', '0', 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z'}
- b := make([]byte, max)
- n, err := io.ReadAtLeast(rand.Reader, b, max)
- if n != max {
- panic(err)
- }
- for i := 0; i < len(b); i++ {
- b[i] = table[int(b[i])%len(table)]
- }
- return prefix + string(b)
- }
- func GenerateRandomNumber(max int) string {
- var table = [...]byte{'1', '2', '3', '4', '5', '6', '7', '8', '9', '0'}
- b := make([]byte, max)
- n, err := io.ReadAtLeast(rand.Reader, b, max)
- if n != max {
- panic(err)
- }
- for i := 0; i < len(b); i++ {
- b[i] = table[int(b[i])%len(table)]
- }
- return string(b)
- }
- func GenerateUserUID(db *gorm.DB, prefix string) string {
- UID := GenerateRandomString(32, prefix)
- var count int64
- for {
- db.Table("user").Where("uid = ?", UID).Count(&count)
- if count == 0 {
- break
- }
- UID = GenerateRandomString(32, prefix)
- }
- return string(UID)
- }
- func GenerateSaleUID(db *gorm.DB, prefix string) string {
- UID := GenerateRandomString(32, prefix)
- var count int64
- for {
- db.Table("sale").Where("uid = ?", UID).Count(&count)
- if count == 0 {
- break
- }
- UID = GenerateRandomString(32, prefix)
- }
- return string(UID)
- }
- func GenerateTokenUID(db *gorm.DB, prefix string) string {
- UID := GenerateRandomString(32, prefix)
- var count int64
- for {
- db.Table("token").Where("uid = ?", UID).Count(&count)
- if count == 0 {
- break
- }
- UID = GenerateRandomString(32, prefix)
- }
- return string(UID)
- }
- func GenerateUserName(db *gorm.DB) string {
- var name string
- var randName = [...]string{"가온해", "겨루", "여우별", "바람꽃", "이플", "소솜", "감또개", "옅구름", "뾰롱뾰롱", "나비잠", "도르레", "미쁘다", "산들림", "소록소록", "도담도담", "가온누리", "이쁘동이", "아슬라", "아리아", "개밥바라기", "다솜", "로운", "나르샤", "미리내", "하늬바람",
- "붙박이별", "그루잠", "여우비", "곰다시", "시나브로", "곰살굳다", "여낙낙하다", "달보드레", "눈바래다", "함초롬하다", "돋을별", "아련나래", "늘품", "아름드리", "넨다하다", "눅진하다", "안다미로", "초련", "닻별", "예그리나", "가시버시", "별하", "누리보듬", "비나리", "씨밀레"}
- idx, err := rand.Int(rand.Reader, big.NewInt(50))
- if err != nil {
- panic(err)
- }
- number, err := rand.Int(rand.Reader, big.NewInt(1000000))
- if err != nil {
- panic(err)
- }
- name = randName[idx.Int64()] + "_" + number.String()
- return name
- }
- // NOTE x 통화 업데이트
- func UpdateCurrency(db *gorm.DB) (error, models.CurrencyPrice) {
- currencyPrice := models.CurrencyPrice{}
- err := db.Find(¤cyPrice).Error
- if errors.Is(err, gorm.ErrRecordNotFound) {
- return err, currencyPrice
- }
- t := time.Now().UTC().In(time.FixedZone("KST", 9*60*60))
- compare := currencyPrice.UpdatedAt.Add(time.Hour * 1)
- if t.After(compare) {
- eth, mf1, mr := ObtainCurrencyPrice()
- if err := db.Model(¤cyPrice).Updates(models.CurrencyPrice{Eth: eth, Mf: mf1, Mr: mr, UpdatedAt: time.Now().UTC()}).Error; err != nil {
- return err, currencyPrice
- }
- }
- return nil, currencyPrice
- }
- func ConvertToId(db *gorm.DB, name string) (uint64, error) {
- _up := models.UserProfile{}
- err := db.Where("name = ?", name).Find(&_up).Error
- if errors.Is(err, gorm.ErrRecordNotFound) {
- return 0, err
- }
- return _up.UserID, nil
- }
- func ConvertToCollectionId(db *gorm.DB, name string) (uint64, error) {
- _cp := models.CollectionProfile{}
- err := db.Where("name = ?", name).Find(&_cp).Error
- if errors.Is(err, gorm.ErrRecordNotFound) {
- return 0, err
- }
- return _cp.CollectionID, nil
- }
- // NOTE x chekc duplicate value
- func DuplicateValue(db *gorm.DB, kind string, name string) (bool, error) {
- type Check struct {
- Name string `json:"name,omitempty"`
- }
- _check := Check{}
- var _table string
- if kind == "user" {
- _table = "user_profile"
- } else {
- _table = "collection_profile"
- }
- err := db.Select("name").Table(_table).Where("name = ?", name).Find(&_check).Error
- if err != nil {
- return true, err
- } else if _check.Name != "" {
- return true, nil
- }
- return false, nil
- }
- // NOTE x make sining
- func MakeSining(db *gorm.DB, info MakeHashData) (operator.MetaRareOperatorNFTVoucher, error) {
- _v := operator.MetaRareOperatorNFTVoucher{
- Signer: common.HexToAddress(info.OwnerAddress),
- TokenAddress: common.HexToAddress(info.CollectionAddress),
- TokenId: big.NewInt(info.TokenID),
- CreationTax: big.NewInt(info.CreationTax),
- Uri: "https://nftinfo.meta-rare.net/",
- TreasuryAddress: common.HexToAddress(info.TreasuryAddress),
- TreasuryTax: big.NewInt(info.PrevTreasuryTax),
- }
- if info.TokenType == "erc721" {
- _v.TokenType = big.NewInt(0)
- _v.Balance = big.NewInt(0)
- _v.TotalBalance = big.NewInt(0)
- } else {
- _v.TokenType = big.NewInt(1)
- _v.Balance = big.NewInt(info.Index)
- _v.TotalBalance = big.NewInt(info.TotalIndex)
- }
- if info.Currency == "eth" {
- _v.AssetAddress = common.HexToAddress("0x0000000000000000000000000000000000000000")
- } else if info.Currency == "mf" {
- _v.AssetAddress = common.HexToAddress(helpers.Addr_metaFinance)
- } else if info.Currency == "mr" {
- _v.AssetAddress = common.HexToAddress(helpers.Addr_metaRare)
- }
- // setting := models.Setting{}
- // _err := db.Find(&setting).Error
- // if errors.Is(_err, gorm.ErrRecordNotFound) {
- // return operator.MetaRareOperatorNFTVoucher{}, _err
- // }
- // _v.TreasuryTax = big.NewInt(int64(setting.Commission) * 100)
- // _v.TreasuryTax = big.NewInt(int64(info.PrevTreasuryTax))
- // _v.TreasuryAddress = common.HexToAddress(setting.TreasuryAddress)
- _v.Price = big.NewInt(10).Mul(big.NewInt(int64(info.Price*100000)), big.NewInt(Decimal13))
- return _v, nil
- }
- func BigPow(a, b int64) *big.Int {
- r := big.NewInt(a)
- return r.Exp(r, big.NewInt(b), nil)
- }
- // SECTION db trasaction
- func DBTransaction(db *gorm.DB) {
- if r := recover(); r != nil {
- db.Rollback()
- }
- }
- /*
- # NOTE x 2차 인증 이메일 발송
- */
- func SendCertificationCode(recipientList string, email string, password string) (string, error) {
- headers := make(map[string]string)
- headers["From"] = email
- headers["To"] = recipientList
- headers["Subject"] = EMAIL_SUBJECT
- message := ""
- for k, v := range headers {
- message += fmt.Sprintf("%s: %s\r", k, v)
- }
- _code := GenerateRandomNumber(6)
- msg := convertToEmailForm(_code)
- message += "\r" + msg
- body := (msg)
- m := gomail.NewMessage()
- // Set E-Mail sender
- m.SetHeader("From", email)
- // Set E-Mail receivers
- m.SetHeader("To", recipientList)
- // Set E-Mail subject
- m.SetHeader("Subject", EMAIL_SUBJECT)
- // Set E-Mail body. You can set plain text or html with text/html
- m.SetBody("text/html", fmt.Sprintf(body))
- // Settings for SMTP server
- d := gomail.NewDialer(EMAIL_HOST, EMAIL_PORT, email, password)
- // This is only needed when SSL/TLS certificate is not valid on server.
- // In production this should be set to false.
- d.TLSConfig = &tls.Config{InsecureSkipVerify: true}
- // Now send E-Mail
- if err := d.DialAndSend(m); err != nil {
- fmt.Println(err)
- panic(err)
- }
- return _code, nil
- }
- func convertToEmailForm(certificationCode string) string {
- convertForm := `<!DOCTYPE html>
- <html lang="en">
- <head>
- <meta charset="UTF-8">
- <meta http-equiv="X-UA-Compatible" content="IE=edge">
- <meta name="viewport" content="width=device-width, initial-scale=1.0">
- <title>Document</title>
- </head>
- <body>
- <div style="display: flex; justify-content: center; align-items: center; flex-direction: column; padding-top : 150px; padding-bottom: 150px; margin-left: 150px;" >
- <div style="border: 1px solid #eeee; width: 800px; background: #FFFFFF 0% 0% no-repeat padding-box; position:relative;">
- <div style="width: 100%; height: 20px; background: transparent linear-gradient(90deg, #F948A0 0%, #789CBB 70%, #16DCCF 100%) 0% 0% no-repeat padding-box;"></div>
- <div style="margin-top : 40px; margin-left: 30px;">
- <img src="https://beta-metarare-image.s3.ap-northeast-2.amazonaws.com/logo.png" />
- </div>
- <div style="margin-right:auto; margin-left: auto; margin-top: 150px; margin-bottom: 100px; height: 56px; width: 500px; text-align: center; color: #000000; font: var(--unnamed-font-style-normal) normal var(--unnamed-font-weight-normal) 20px/32px D-DIN Exp; font: normal normal normal 25px/37px D-DIN Exp;letter-spacing: -0.6px;">출금을 위한 인증코드입니다.<br>인증코드 입력 창에 아래 내용을 입력해주세요.</div>
- <div style="display: flex; text-align: center;
- justify-content: center;
- flex-direction: column;
- margin-right:auto;
- margin-left: auto;
- background: #F5F5F5 0% 0% no-repeat padding-box;
- border: 1px solid #F5F5F5;
- border-radius: 28px;
- width: 350px;
- height: 50px;
- opacity: 1;
- font: var(--unnamed-font-style-normal) normal var(--unnamed-font-weight-bold) var(--unnamed-font-size-14)/15px PT Mono; letter-spacing: var(--unnamed-character-spacing--0-42); color: var(--unnamed-color-000000); font: normal normal bold 16px/15px PT Mono; letter-spacing: -0.42px; color: #000000; opacity: 1;">
- <p style="padding-left: 150px">` + certificationCode + `</p>
- </div>
- <div style="width: 500px;
- margin-left: auto;
- margin-right: auto;
- margin-top: 50px;
- margin-bottom: 50px;
- text-align: center;
- letter-spacing: -0.39px;
- color: #22BCB2;
- opacity: 1;
- letter-spacing: var(--unnamed-character-spacing--0-39);
- text-align: center;
- font: normal normal normal 20px/34px D-DIN Exp;
- color: #22BCB2;">"본 인증코드는 본인인증 및 출금을 위한 용도이며,<br>제 3자에게 공유 및 유출되었을 시 책임지지 않습니다.
- </div>
- <div style="
- width: 800px;
- background: #F5F5F5 0% 0% no-repeat padding-box;
- opacity: 1;
- height: 180px;
- justify-content: center;
- flex-direction: column;
- text-align: center;
- font: var(--unnamed-font-style-normal) normal var(--unnamed-font-weight-normal) var(--unnamed-font-size-12)/var(--unnamed-line-spacing-14) var(--unnamed-font-family-pretendard-variable);
- letter-spacing: var(--unnamed-character-spacing--0-36);
- color: var(--unnamed-color-888888);
- text-align: center;
- font: normal normal normal 16px/8px Pretendard Variable;
- letter-spacing: -0.36px;
- color: #888888;
- opacity: 1;">
- <p style="padding-top:85px;">@ MetaRare. Inc. All rights reserved.</p>
- </div>
- </div>
- </div>
- </body>
- </html>`
- return convertForm
- }
|