common-func.go 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533
  1. //go:build !dev
  2. // +build !dev
  3. package locals
  4. import (
  5. "bytes"
  6. "crypto/sha256"
  7. "encoding/base64"
  8. "encoding/json"
  9. "errors"
  10. "fmt"
  11. "io/ioutil"
  12. "kkscrap-go/locals/gosodium/cryptobox"
  13. "net/http"
  14. "strings"
  15. "time"
  16. "github.com/dabory/abango-rest"
  17. e "github.com/dabory/abango-rest/etc"
  18. "github.com/go-xorm/xorm"
  19. "github.com/microcosm-cc/bluemonday"
  20. )
  21. const (
  22. // Tpf string = "dbr_" // TablePrefix
  23. //QueryComment
  24. QcWhere string = "-- @where"
  25. QcSubWhere string = "-- @subwhere"
  26. QcHaving string = "-- @having"
  27. QcOrder string = "-- @order"
  28. QcLimitOffset string = "-- @limitoffset"
  29. QcExtract string = "-- @extract:"
  30. QcClosed string = "-- @closed:"
  31. QcDelivery string = "-- @delivery:"
  32. QcBetweenDates string = "-- @between_dates"
  33. QcEnd string = "--" //QueryComment
  34. //QueryKeyword
  35. QkWhere string = "\nwhere true "
  36. // QkWhere string = "\nwhere 1 "
  37. QkHaving string = "\nhaving true "
  38. QkOrder string = "\norder by "
  39. QkLimit string = "\nlimit "
  40. QkOffset string = " offset "
  41. QkTmpOrder string = " order by is_sum desc, t_id asc "
  42. )
  43. type AppApi struct {
  44. ApiUrl string
  45. GateToken string
  46. }
  47. // 0:Sso, 1:Dbu 매우 중요하다.
  48. var gAppApis [2]AppApi
  49. var (
  50. SQL_DEBUG bool
  51. NORMAL_DEBUG bool
  52. )
  53. var BlockNoCnt int
  54. // type GateTokenGetReq struct {
  55. // ClientId string
  56. // BeforeBase64 string
  57. // AppBase64 string
  58. // }
  59. func (y *SyncController) Init() error {
  60. var kPairStr string
  61. if abango.XConfig["IsLocalKeyPair"] != "Yes" {
  62. keypair, err := GuestKeyPairGet(abango.XConfig["SyncClientId"])
  63. if err != nil {
  64. return e.ErrLog(e.FuncRun("03joau0u3qd", e.CurrFuncName()), err)
  65. }
  66. kPairStr = keypair
  67. fmt.Println("RemoteKeypair:", kPairStr)
  68. } else {
  69. kPairStr = abango.XConfig["LocalKeyPair"]
  70. fmt.Println("LocalKeyPair:", kPairStr)
  71. }
  72. keyPair, err := base64.StdEncoding.DecodeString(kPairStr)
  73. if err != nil {
  74. return e.ErrLog(e.FuncRun("joiuejcsoe: Decryption Failure-1 ", e.CurrFuncName()), err)
  75. }
  76. sKey, pKey, err := cryptobox.CryptoBoxGetSecretPublicKeyFrom(keyPair)
  77. if err != nil {
  78. return e.ErrLog(e.FuncRun("joiuejcsoe: Decryption Failure-2 ", e.CurrFuncName()), err)
  79. }
  80. decodedBytes, err := base64.StdEncoding.DecodeString(abango.XConfig["SyncBB64"])
  81. if err != nil {
  82. return e.ErrLog(e.FuncRun("joiuejcsoe: Decryption Failure-3 ", e.CurrFuncName()), err)
  83. }
  84. //decrypt 문제는 여기서 memory error 가 난다.
  85. decryptedBytes, boxRet := cryptobox.CryptoBoxSealOpen(decodedBytes, pKey, sKey)
  86. if boxRet != 0 {
  87. return e.ErrLog(e.FuncRun("joiuejcsoe: Decryption Failure-4(Wrong BB64Key) ", e.CurrFuncName()), err)
  88. }
  89. vmc := &struct {
  90. Driver string
  91. Host string
  92. Port int
  93. Username string
  94. Database string
  95. Password string
  96. }{}
  97. if err := json.Unmarshal(decryptedBytes, vmc); err != nil {
  98. return e.ErrLog(e.FuncRun("joiuejcsoe: Decryption Failure-5 ", e.CurrFuncName()), err)
  99. }
  100. connStr := vmc.Username + ":" + vmc.Password + "@tcp(" + vmc.Host + ":" + e.NumToStr(vmc.Port) + ")/" + vmc.Database
  101. fmt.Println("connStr:", connStr)
  102. y.Scb.ConnString = connStr
  103. if y.Db, err = xorm.NewEngine(abango.XConfig["DbType"], connStr); err != nil {
  104. return e.ErrLog(e.FuncRun("309upajs3w: DBEngine Open Error ", e.CurrFuncName()), err)
  105. }
  106. var connHint string
  107. strArr := strings.Split(connStr, "@tcp")
  108. if len(strArr) == 2 {
  109. connHint = strArr[1]
  110. } else {
  111. return e.ErrLog(e.FuncRun("309upajs3w: connString format mismatch: "+strArr[1], e.CurrFuncName()), err)
  112. }
  113. y.Db.ShowSQL(false)
  114. y.Db.SetMaxOpenConns(100)
  115. y.Db.SetMaxIdleConns(20)
  116. y.Db.SetConnMaxLifetime(60 * time.Second)
  117. if _, err := y.Db.IsTableExist("aaa"); err == nil {
  118. e.OkLog("SyncDB connection in " + connHint)
  119. return nil
  120. } else {
  121. return e.ErrLog(e.FuncRun("93haoy93d: SyncDB connection Fail in "+connHint+": ", e.CurrFuncName()), err)
  122. }
  123. }
  124. type (
  125. MemoryMap map[string]interface{}
  126. MapStore struct {
  127. store MemoryMap
  128. }
  129. )
  130. func (c *MapStore) Get(key string) interface{} {
  131. return c.store[key]
  132. }
  133. func (c *MapStore) Set(key string, val interface{}) {
  134. if c.store == nil {
  135. c.store = make(MemoryMap)
  136. }
  137. c.store[key] = val
  138. }
  139. func DbrPasswd(password string, salt string) string {
  140. salt16 := DbrSaltBase(salt, 16)
  141. var passwordBytes = []byte(password)
  142. var sha256Hasher = sha256.New()
  143. passwordBytes = append(passwordBytes, salt16...)
  144. sha256Hasher.Write(passwordBytes)
  145. var hashedPasswordBytes = sha256Hasher.Sum(nil)
  146. var base64EncodedPasswordHash = base64.URLEncoding.EncodeToString(hashedPasswordBytes)
  147. return base64EncodedPasswordHash
  148. }
  149. func DbrHashedIndex(target string) string {
  150. //!!중요: salt는 16char에서만 작동된다. hash 값은 44 char나오지만 32char로 잘라서 쓴다.
  151. fmt.Println("hash_full_length:", DbrPasswd(target, "$$hashed_index$$"))
  152. return DbrPasswd(target, "$$hashed_index$$")[0:32]
  153. }
  154. func DbrCompare(hashedPassword, currPassword string, salt string) bool {
  155. // fmt.Println("salt:", salt)
  156. // fmt.Println("currPassword:", currPassword)
  157. var currPasswordHash = DbrPasswd(currPassword, salt)
  158. // fmt.Println("currPasswordHash:", currPasswordHash)
  159. // fmt.Println("hashedPassword:", hashedPassword)
  160. return hashedPassword == currPasswordHash
  161. }
  162. func DbrSaltBase(salt string, saltSize int) []byte { //어떤 사이즈라도 16byte의 Base64로 변경
  163. tmp := []byte(salt)
  164. salt64 := base64.StdEncoding.EncodeToString(tmp)
  165. return []byte(salt64[4 : saltSize+4])
  166. }
  167. func HasPickActPage(uri string, table string) bool {
  168. if table == "member" {
  169. if uri == "/"+table+"-pick" || uri == "/"+table+"-act" || uri == "/"+table+"-page" || uri == "/"+table+"-secured-pick" || uri == "/"+table+"-secured-page" || uri == "/"+table+"-secured-act" {
  170. return true
  171. } else {
  172. return false
  173. }
  174. } else {
  175. if uri == "/"+table+"-pick" || uri == "/"+table+"-act" || uri == "/"+table+"-page" {
  176. return true
  177. } else {
  178. return false
  179. }
  180. }
  181. }
  182. // func ByteIndex(ba *[]byte, bt byte, opt int) int {
  183. // if opt == 0 { //normal
  184. // for i := 0; i < len(*ba); i++ {
  185. // if (*ba)[i] == bt {
  186. // return i
  187. // }
  188. // }
  189. // } else if opt == 1 { //rerverse
  190. // for i := len(*ba) - 1; i > 0; i-- {
  191. // if (*ba)[i] == bt {
  192. // return i
  193. // }
  194. // }
  195. // }
  196. // return -1
  197. // }
  198. func LastQry(qry xorm.Session) string {
  199. ret, _ := qry.LastSQL()
  200. fmt.Println("\n" + ret + "\n")
  201. return ret
  202. }
  203. func ShowQry(qry xorm.Session, qryName string) string {
  204. if SQL_DEBUG {
  205. ret, _ := qry.LastSQL()
  206. return e.LogStr("", "ShowQry===["+qryName+"]==="+"\n[ "+ret+" ]\n")
  207. }
  208. return ""
  209. }
  210. func ShowSql(sqlStr string, qryName string) string {
  211. if SQL_DEBUG {
  212. return e.LogStr("", "ShowSql===["+qryName+"]==="+"\n[ "+sqlStr+" ]\n")
  213. }
  214. return ""
  215. }
  216. // func ShowDebug(debugStr string, index string) string {
  217. // if NORMAL_DEBUG {
  218. // return e.LogStr("", "ShowDebug===["+index+"]==="+"\n[ "+debugStr+" ]\n")
  219. // }
  220. // return ""
  221. // }
  222. func QryDirName(qryName string) (string, string) {
  223. if !strings.Contains(qryName, "::") {
  224. return "queries/", qryName
  225. } else {
  226. q := strings.Split(qryName, "::")
  227. return "queries/themes/" + q[0] + "/", q[1]
  228. }
  229. }
  230. func StripHtml(cont string, max int) string {
  231. p := bluemonday.StripTagsPolicy()
  232. s := p.Sanitize(cont)
  233. if len(s) > max {
  234. return string([]rune(s)[:max])
  235. } else {
  236. return s
  237. }
  238. }
  239. func Sanitize(cont string) string {
  240. p := bluemonday.UGCPolicy()
  241. return p.Sanitize(cont)
  242. }
  243. func AddStrIfNotExist(s *string, target string) {
  244. if !strings.Contains(*s, target) {
  245. *s += target
  246. }
  247. }
  248. func HttpResponseSimplePost(method string, apiurl string, jsBytes []byte) (retbody []byte, retsta int, reterr error) {
  249. response, err := http.Post(apiurl, "application/json", bytes.NewBuffer(jsBytes))
  250. if err != nil {
  251. return nil, 0, errors.New(e.FuncRunErr("65rfg0csdew", "The HTTP request failed with error "+e.CurrFuncName()+err.Error()))
  252. } else {
  253. retbody, err = ioutil.ReadAll(response.Body)
  254. if err != nil {
  255. return nil, 0, errors.New(e.FuncRunErr("kjda89382", "ReadAll error "+e.CurrFuncName()+err.Error()))
  256. }
  257. }
  258. return retbody, response.StatusCode, nil
  259. }
  260. func HttpResponseWithGt(method string, apiurl string, jsBytes []byte, gateToken string) (retbody []byte, retsta int, reterr error) {
  261. reader := bytes.NewBuffer(jsBytes)
  262. req, err := http.NewRequest(method, apiurl, reader)
  263. if err != nil {
  264. return nil, 909, e.ErrLog(e.FuncRun("xcawrq3276fa-http.NewRequest "+apiurl, e.CurrFuncName()), err)
  265. }
  266. req.Header.Add("RemoteIp", "localhost")
  267. req.Header.Add("Referer", "http://localhost")
  268. req.Header.Add("GateToken", gateToken)
  269. req.Body = ioutil.NopCloser(bytes.NewReader(jsBytes))
  270. // Client객체에서 Request 실행
  271. client := &http.Client{
  272. Timeout: time.Second * 20, //Otherwirse, it can cause crash without this line. Must Must.
  273. } // Normal is 10 but extend 20 on 1 Dec 2018
  274. // fmt.Println(reflect.TypeOf(respo))
  275. resp, err := client.Do(req)
  276. if err != nil {
  277. return nil, 909, e.ErrLog(e.FuncRun("wewer2354e-client.Do "+apiurl, e.CurrFuncName()), err)
  278. }
  279. defer resp.Body.Close()
  280. byteRtn, _ := ioutil.ReadAll(resp.Body)
  281. return byteRtn, resp.StatusCode, nil
  282. }
  283. func GuestGateTokenGet(appType int, pivotUrl string, ab64 string) (string, string, error) {
  284. if gAppApis[appType].GateToken == "" {
  285. req := &struct {
  286. AppType string
  287. AppBase64 string
  288. }{
  289. AppType: "Main",
  290. AppBase64: ab64,
  291. }
  292. bodyBytes, _ := json.Marshal(req)
  293. apiUrl := pivotUrl + "/gate-token-get"
  294. msgBytes, staInt, err := HttpResponseSimplePost("POST", apiUrl, bodyBytes)
  295. // fmt.Println("apiUrl:", apiUrl)
  296. // fmt.Println("bodyBytes:", string(bodyBytes))
  297. if err != nil {
  298. return "", "", e.ErrLog(e.FuncRun("45425fd34sd-The HTTP request "+apiUrl, e.CurrFuncName()), err)
  299. }
  300. if staInt != 200 {
  301. return "", "", errors.New(e.FuncRun("87ty344ra3-Request Fail "+string(msgBytes), e.CurrFuncName()))
  302. }
  303. ret := &struct {
  304. ApiUrl string
  305. GateToken string
  306. }{}
  307. if err := json.Unmarshal(msgBytes, ret); err != nil {
  308. return "", "", e.ErrLog(e.FuncRun("45425fd34sd-Json Format "+apiUrl, e.CurrFuncName()), err)
  309. }
  310. gAppApis[appType].ApiUrl = ret.ApiUrl
  311. gAppApis[appType].GateToken = ret.GateToken
  312. } else {
  313. fmt.Println("GateToken already is in the ARRAY")
  314. }
  315. // fmt.Println("gSsoApiUrl:", gSsoApiUrl)
  316. // fmt.Println("gSsoGateToken:", gSsoGateToken)
  317. return gAppApis[appType].ApiUrl, gAppApis[appType].GateToken, nil
  318. }
  319. func GuestEncryptGet(code string) (string, string, error) {
  320. appType := 1 //Dbupdate
  321. req := &struct {
  322. EncryptCode string
  323. }{
  324. EncryptCode: code,
  325. }
  326. // 0:Sso, 1:Dbu
  327. pivotUrl, gateToken, err := GuestGateTokenGet(appType, abango.XConfig["DbuConnString"], abango.XConfig["DbuAppBase64"])
  328. if err != nil {
  329. return "", "", e.ErrLog(e.FuncRun("23rfsr3qrase", e.CurrFuncName()), err)
  330. }
  331. ret := &struct {
  332. EncrypteKey string
  333. SaltKey string
  334. }{}
  335. bodyBytes, _ := json.Marshal(req)
  336. apiUrl := pivotUrl + "/encrypt-get"
  337. msgBytes, staInt, err := HttpResponseWithGt("POST", apiUrl, bodyBytes, gateToken)
  338. if err != nil {
  339. return "", "", e.ErrLog(e.FuncRun("1eadwrq34dxc-The HTTP request "+apiUrl, e.CurrFuncName()), err)
  340. }
  341. if staInt != 200 {
  342. gAppApis[appType].GateToken = "" // GateToke Expired 경우 Clear 한다.
  343. return "", "", errors.New(e.FuncRun("45faw3rfw-Request Fail "+string(msgBytes), e.CurrFuncName()))
  344. }
  345. if err := json.Unmarshal(msgBytes, ret); err != nil {
  346. return "", "", e.ErrLog(e.FuncRun("6756er345r3", e.CurrFuncName()), err)
  347. }
  348. return ret.EncrypteKey, ret.SaltKey, nil
  349. }
  350. func GuestAvailDbupdateGet(lastno string, isskipup string) ([]byte, error) {
  351. appType := 1 //Dbupdate
  352. req := &struct {
  353. DbupdateNo string
  354. IsSkipUpdate string
  355. }{
  356. DbupdateNo: lastno,
  357. IsSkipUpdate: isskipup,
  358. }
  359. // 0:Sso, 1:Dbu
  360. pivotUrl, gateToken, err := GuestGateTokenGet(appType, abango.XConfig["DbuConnString"], abango.XConfig["DbuAppBase64"])
  361. if err != nil {
  362. return nil, e.ErrLog(e.FuncRun("23rfsr3qrase", e.CurrFuncName()), err)
  363. }
  364. bodyBytes, _ := json.Marshal(req)
  365. apiUrl := pivotUrl + "/avail-dbupdate-get"
  366. msgBytes, staInt, err := HttpResponseWithGt("POST", apiUrl, bodyBytes, gateToken)
  367. if err != nil {
  368. return nil, e.ErrLog(e.FuncRun("1eadwrq34dxc-The HTTP request "+apiUrl, e.CurrFuncName()), err)
  369. }
  370. if staInt != 200 {
  371. gAppApis[appType].GateToken = "" // GateToke Expired 경우 Clear 한다.
  372. return nil, errors.New(e.FuncRun("0asfweijcvs-Request Fail "+string(msgBytes), e.CurrFuncName()))
  373. }
  374. return msgBytes, nil
  375. }
  376. func GuestKeyPairGet(clientId string) (string, error) {
  377. appType := 0 //Dbupdate
  378. req := &struct {
  379. ClientId string
  380. }{
  381. ClientId: clientId,
  382. }
  383. // fmt.Println("clientId:", clientId)
  384. // 0:Sso, 1:Dbu
  385. pivotUrl, gateToken, err := GuestGateTokenGet(appType, abango.XConfig["SsoConnString"], abango.XConfig["SsoAppBase64"])
  386. if err != nil {
  387. return "", e.ErrLog(e.FuncRun("23rfsr3qrase", e.CurrFuncName()), err)
  388. }
  389. ret := &struct {
  390. KeyPair string
  391. }{}
  392. bodyBytes, _ := json.Marshal(req)
  393. apiUrl := pivotUrl + "/key-pair-get"
  394. msgBytes, staInt, err := HttpResponseWithGt("POST", apiUrl, bodyBytes, gateToken)
  395. if err != nil {
  396. return "", e.ErrLog(e.FuncRun("1eadwrq34dxc-The HTTP request "+apiUrl, e.CurrFuncName()), err)
  397. }
  398. if staInt != 200 {
  399. gAppApis[appType].GateToken = "" // GateToke Expired 경우 Clear 한다.
  400. return "", errors.New(e.FuncRun("09665gsre3-Request Fail "+string(msgBytes), e.CurrFuncName()))
  401. }
  402. if err := json.Unmarshal(msgBytes, ret); err != nil {
  403. return "", e.ErrLog(e.FuncRun("9074tf32de", e.CurrFuncName()), err)
  404. }
  405. return ret.KeyPair, nil
  406. }
  407. func OneRowQuery(y *abango.Controller, sql string) (c1 string, c2 string, c3 string, err error) {
  408. page, err := y.Db.Query(sql)
  409. if err != nil {
  410. return "", "", "", errors.New(e.FuncRunErr("0hjnboisqow", e.CurrFuncName()+err.Error()))
  411. }
  412. if len(page) > 1 {
  413. return "", "", "", errors.New(e.FuncRunErr("0k1dt6j3d", e.CurrFuncName()+"Row Count > 1 "))
  414. }
  415. for _, row := range page {
  416. c1 = string(row["c1"])
  417. c2 = string(row["c2"])
  418. c3 = string(row["c3"])
  419. }
  420. return
  421. }
  422. func IsFirstOrderGet(y *abango.Controller, buyerId int) string {
  423. qry := fmt.Sprintf("select count(*) as c1 from dbr_sorder where buyer_id = %d ", buyerId)
  424. ordCnt, _, _, _ := OneRowQuery(y, qry)
  425. if ordCnt == "1" {
  426. return "1"
  427. } else {
  428. return "0"
  429. }
  430. }
  431. func TimeFormatGet(format string) string {
  432. rtn := ""
  433. if format == "" {
  434. rtn = "060102"
  435. } else if format == "YYMMDD" {
  436. rtn = "060102"
  437. } else if format == "YYYYMMDD" {
  438. rtn = "20060102"
  439. } else if format == "YY-MM-DD" {
  440. rtn = "06-01-02"
  441. } else if format == "YY.MM.DD" {
  442. rtn = "06.01.02"
  443. } else if format == "YYMM" {
  444. rtn = "0601"
  445. } else if format == "YY" {
  446. rtn = "06"
  447. }
  448. return rtn
  449. }