common-func.go 14 KB

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