func (c *Controller) GenerateNewNodeKey() (string, error) { if c.SessRestricted != 0 { return "", utils.ErrInfo(errors.New("Permission denied")) } priv, pub := utils.GenKeys() json, err := json.Marshal(map[string]string{"private_key": priv, "public_key": pub}) if err != nil { return "", utils.ErrInfo(err) } log.Debug("%v", json) return string(json), nil }
func (c *Controller) GenerateNewPrimaryKey() (string, error) { c.r.ParseForm() password := c.r.FormValue("password") priv, pub := utils.GenKeys() if len(password) > 0 { log.Debug("priv:", priv) encKey, err := utils.Encrypt(utils.Md5("11"), []byte(priv)) log.Debug("priv encKey:", encKey) if err != nil { return "", utils.ErrInfo(err) } priv = base64.StdEncoding.EncodeToString(encKey) log.Debug("priv ENC:", priv) //priv = string(encKey) } json, err := json.Marshal(map[string]string{"private_key": priv, "public_key": pub, "password_hash": string(utils.DSha256(password))}) if err != nil { return "", utils.ErrInfo(err) } log.Debug("%v", json) return string(json), nil }
func (a *AvailablekeyStruct) GetAvailableKey() (int64, string, error) { community, err := a.GetCommunityUsers() if err != nil { return 0, "", utils.ErrInfo(err) } // запрещено менять ключ таким методом если в my_table уже есть статус if len(community) == 0 { status, err := a.Single("SELECT status FROM my_table").String() if err != nil { return 0, "", utils.ErrInfo(err) } if status != "my_pending" { return 0, "", utils.ErrInfo(errors.New("my_table not null")) } } var keys []string for i := 0; i < 10; i++ { keysStr, err := utils.GetHttpTextAnswer("http://dcoin.club/keys") if err != nil { return 0, "", utils.ErrInfo(err) } //keysStr = strings.Replace(keysStr, "\n", "", -1) r, _ := regexp.Compile("(?s)-----BEGIN RSA PRIVATE KEY-----(.*?)-----END RSA PRIVATE KEY-----") keys = r.FindAllString(keysStr, -1) for i := range keys { j := rand.Intn(i + 1) keys[i], keys[j] = keys[j], keys[i] } if len(keys) > 0 { break } else { utils.Sleep(5) } } for _, key := range keys { userId, pubKey, err := a.checkAvailableKey(key) if err != nil { log.Error("%s", utils.ErrInfo(err)) // тут ошибка - это нормально } log.Debug("checkAvailableKey userId: %v", userId) if userId > 0 { // запишем приватный ключ в БД, чтобы можно было подписать тр-ию на смену ключа myPref := "" log.Debug("schema_ 0") if len(community) > 0 { schema_ := &schema.SchemaStruct{} schema_.DCDB = a.DCDB schema_.DbType = a.ConfigIni["db_type"] schema_.PrefixUserId = int(userId) schema_.GetSchema() myPref = utils.Int64ToStr(userId) + "_" err = a.ExecSql("INSERT INTO "+myPref+"my_table (user_id, status, email) VALUES (?, ?, ?)", userId, "waiting_set_new_key", a.Email) if err != nil { return 0, "", utils.ErrInfo(err) } err = a.ExecSql("INSERT INTO community ( user_id ) VALUES ( ? )", userId) if err != nil { return 0, "", utils.ErrInfo(err) } } else { err = a.ExecSql("UPDATE my_table SET user_id = ?, status = ?", userId, "waiting_set_new_key") if err != nil { return 0, "", utils.ErrInfo(err) } } log.Debug("schema_ 1") // пишем приватный в my_keys т.к. им будем подписывать тр-ию на смену ключа err = a.ExecSql("INSERT INTO "+myPref+"my_keys (private_key, public_key, status, block_id) VALUES (?, [hex], ?, ?)", key, pubKey, "approved", 1) if err != nil { return 0, "", utils.ErrInfo(err) } log.Debug("GenKeys 0") newPrivKey, newPubKey := utils.GenKeys() log.Debug("GenKeys 1") // сразу генерируем новый ключ и пишем приватный временно в my_keys, чтобы можно было выдавать юзеру для скачивания err = a.ExecSql("INSERT INTO "+myPref+"my_keys (private_key, public_key, status) VALUES (?, ?, ?)", newPrivKey, utils.HexToBin([]byte(newPubKey)), "my_pending") if err != nil { return 0, "", utils.ErrInfo(err) } log.Debug("return userId %d", userId) return userId, pubKey, nil } } return 0, "", nil }
func (c *Controller) MiningMenu() (string, error) { var err error log.Debug("first_select: %v", c.Parameters["first_select"]) if c.Parameters["first_select"] == "1" { c.ExecSql(`UPDATE ` + c.MyPrefix + `my_table SET first_select=1`) } if len(c.Parameters["skip_promised_amount"]) > 0 { err = c.ExecSql("UPDATE " + c.MyPrefix + "my_table SET hide_first_promised_amount = 1") if err != nil { return "", utils.ErrInfo(err) } } if len(c.Parameters["skip_commission"]) > 0 { err = c.ExecSql("UPDATE " + c.MyPrefix + "my_table SET hide_first_commission = 1") if err != nil { return "", utils.ErrInfo(err) } } var result string checkCommission := func() error { // установлена ли комиссия commission, err := c.Single("SELECT commission FROM commission WHERE user_id = ?", c.SessUserId).String() if err != nil { return utils.ErrInfo(err) } if len(commission) == 0 { // возможно юзер уже отправил запрос на добавление комиссии last_tx, err := c.GetLastTx(c.SessUserId, utils.TypesToIds([]string{"ChangeCommission"}), 1, c.TimeFormat) if err != nil { return utils.ErrInfo(err) } if len(last_tx) > 0 && (len(last_tx[0]["queue_tx"]) > 0 || len(last_tx[0]["tx"]) > 0) { // авансом выдаем полное майнерское меню result = "full_mining_menu" } else { // возможно юзер нажал кнопку "пропустить" hideFirstCommission, err := c.Single("SELECT hide_first_commission FROM " + c.MyPrefix + "my_table").Int64() if err != nil { return utils.ErrInfo(err) } if hideFirstCommission == 0 { result = "need_commission" } else { result = "full_mining_menu" } } } else { result = "full_mining_menu" } return nil } hostTpl := "" // чтобы при добавлении общенных сумм, смены комиссий редиректило сюда navigate := "miningMenu" if c.SessRestricted != 0 { result = "need_email" } else { myMinerId, err := c.Single("SELECT miner_id FROM miners_data WHERE user_id = ?", c.SessUserId).Int64() if err != nil { return "", utils.ErrInfo(err) } if myMinerId == 0 { // проверим, послали ли мы запрос в DC-сеть data, err := c.OneRow("SELECT node_voting_send_request, http_host as host FROM " + c.MyPrefix + "my_table").String() if err != nil { return "", utils.ErrInfo(err) } node_voting_send_request := utils.StrToInt64(data["node_voting_send_request"]) host := data["host"] // если прошло менее 1 часа if time.Now().Unix()-node_voting_send_request < 3600 { result = "pending" } else if node_voting_send_request > 0 { // голосование нодов nodeVotesEnd, err := c.Single("SELECT votes_end FROM votes_miners WHERE user_id = ? AND type = 'node_voting' ORDER BY id DESC", c.SessUserId).String() if err != nil { return "", utils.ErrInfo(err) } if nodeVotesEnd == "1" { // голосование нодов завершено userVotesEnd, err := c.Single("SELECT votes_end FROM votes_miners WHERE user_id = ? AND type = 'user_voting' ORDER BY id DESC", c.SessUserId).String() if err != nil { return "", utils.ErrInfo(err) } if userVotesEnd == "1" { // юзерское голосование закончено result = "bad" } else if userVotesEnd == "0" { // идет юзерское голосование result = "users_pending" } else { result = "bad_photos_hash" hostTpl = host } } else if nodeVotesEnd == "0" && time.Now().Unix()-node_voting_send_request < 86400 { // голосование нодов началось, ждем. result = "nodes_pending" } else if nodeVotesEnd == "0" && time.Now().Unix()-node_voting_send_request >= 86400 { // голосование нодов удет более суток и еще не завершилось result = "resend" } else { // запрос в DC-сеть еще не дошел и голосования не начались // если прошло менее 1 часа if time.Now().Unix()-node_voting_send_request < 3600 { result = "pending" } else { // где-то проблема и запрос не ушел. result = "resend" } } } else { // запрос на получение статуса "майнер" мы еще не слали result = "null" } } else { // установлены ли уведомления smtpUserName, err := c.Single("SELECT smtp_username FROM " + c.MyPrefix + "my_table").String() if err != nil { return "", utils.ErrInfo(err) } if len(smtpUserName) == 0 { result = "need_notifications" } else { // добавлена ли обещанная сумма promisedAmount, err := c.Single("SELECT id FROM promised_amount WHERE user_id = ?", c.SessUserId).Int64() if err != nil { return "", utils.ErrInfo(err) } if promisedAmount == 0 { // возможно юзер уже отправил запрос на добавление обещенной суммы last_tx, err := c.GetLastTx(c.SessUserId, utils.TypesToIds([]string{"NewPromisedAmount"}), 1, c.TimeFormat) if len(last_tx) > 0 && (len(last_tx[0]["queue_tx"]) > 0 || len(last_tx[0]["tx"]) > 0) { // установлена ли комиссия err = checkCommission() if err != nil { return "", utils.ErrInfo(err) } } else { // возможно юзер нажал кнопку "пропустить" hideFirstPromisedAmount, err := c.Single("SELECT hide_first_promised_amount FROM " + c.MyPrefix + "my_table").Int64() if err != nil { return "", utils.ErrInfo(err) } if hideFirstPromisedAmount == 0 { result = "need_promised_amount" } else { err = checkCommission() if err != nil { return "", utils.ErrInfo(err) } } } } else { // установлена ли комиссия err = checkCommission() if err != nil { return "", utils.ErrInfo(err) } } } } } var minerVotesAttempt int64 var myComments []map[string]string c.Navigate = navigate lastTxFormatted := "" tplName := "" tplTitle := "" log.Debug(">result:", result) var nodePrivateKey string if result == "null" { tplName = "upgrade_0" tplTitle = "upgrade0" return c.Upgrade0() } else if result == "need_email" { tplName = "sign_up_in_the_pool" tplTitle = "signUpInThePool" // сгенерим ключ для нода nodePrivateKey, _ = utils.GenKeys() } else if result == "need_notifications" { tplName = "notifications" tplTitle = "notifications" return c.Notifications() } else if result == "need_promised_amount" { tplName = "promised_amount_add" tplTitle = "upgrade" return c.NewPromisedAmount() } else if result == "need_commission" { tplName = "change_commission" tplTitle = "changeCommission" return c.ChangeCommission() } else if result == "full_mining_menu" { tplName = "mining_menu" tplTitle = "miningMenu" last_tx, err := c.GetLastTx(c.SessUserId, utils.TypesToIds([]string{"NewUser", "NewMiner", "NewPromisedAmount", "ChangePromisedAmount", "VotesMiner", "ChangeGeolocation", "VotesPromisedAmount", "DelPromisedAmount", "CashRequestOut", "CashRequestIn", "VotesComplex", "ForRepaidFix", "NewHolidays", "ActualizationPromisedAmounts", "Mining", "NewMinerUpdate", "ChangeHost", "ChangeCommission"}), 3, c.TimeFormat) if err != nil { return "", utils.ErrInfo(err) } if len(last_tx) > 0 { lastTxFormatted, _ = utils.MakeLastTx(last_tx, c.Lang) } } else { // сколько у нас осталось попыток стать майнером. countAttempt, err := c.CountMinerAttempt(c.SessUserId, "user_voting") if err != nil { return "", utils.ErrInfo(err) } minerVotesAttempt = c.Variables.Int64["miner_votes_attempt"] - countAttempt // комментарии проголосовавших myComments, err = c.GetAll(`SELECT * FROM `+c.MyPrefix+`my_comments WHERE comment != 'null' AND type NOT IN ('arbitrator','seller')`, -1) tplName = "upgrade" tplTitle = "upgrade" } log.Debug("tplName, tplTitle %v, %v", tplName, tplTitle) TemplateStr, err := makeTemplate(tplName, tplTitle, &miningMenuPage{ Alert: c.Alert, Lang: c.Lang, CountSignArr: c.CountSignArr, ShowSignData: c.ShowSignData, UserId: c.SessUserId, SignData: "", CurrencyList: c.CurrencyList, LastTxFormatted: lastTxFormatted, MyComments: myComments, Result: result, NodePrivateKey: nodePrivateKey, MinerVotesAttempt: minerVotesAttempt, Mobile: utils.Mobile(), Host: hostTpl}) if err != nil { return "", utils.ErrInfo(err) } return TemplateStr, nil }
func (c *Controller) Upgrade6() (string, error) { log.Debug("Upgrade6") var hostType string hostData, err := c.OneRow("SELECT http_host, tcp_host FROM " + c.MyPrefix + "my_table").String() if err != nil { return "", utils.ErrInfo(err) } // в режиме пула выдаем только хост ноды log.Debug("c.Community: %v", c.Community) log.Debug("c.PoolAdminUserId: %v", c.PoolAdminUserId) if c.Community /*&& len(data["http_host"]) == 0 && len(data["tcp_host"]) == 0*/ { hostType = "pool" hostData, err = c.OneRow("SELECT http_host, tcp_host FROM miners_data WHERE user_id = ?", c.PoolAdminUserId).String() if err != nil { return "", utils.ErrInfo(err) } if len(hostData) == 0 { hostData["http_host"] = "null http_host in miners_data" hostData["tcp_host"] = "null tcp_host in miners_data" } } else { // если смогли подключиться из вне ip, err := utils.GetHttpTextAnswer("http://api.ipify.org") if err != nil { return "", utils.ErrInfo(err) } /*httpHost, err := c.Single("SELECT http_host FROM "+c.MyPrefix+"my_table").String() if err!=nil { return "", utils.ErrInfo(err) } port := "8089" if len(httpHost) > 0 { re := regexp.MustCompile(`https?:\/\/(?:[0-9a-z\_\.\-]+):([0-9]+)`) match := re.FindStringSubmatch(httpHost) if len(match) != 0 { port = match[1]; } }*/ conn, err := net.DialTimeout("tcp", ip+":8089", 3*time.Second) log.Debug("ip: %v", ip) if err != nil { // если не смогли подключиться, то в JS будем искать рабочий пул и региться на нем. и дадим юзеру указать другие хост:ip hostType = "findPool" } else { hostType = "normal" defer conn.Close() hostData["http_host"] = ip + ":8089" hostData["tcp_host"] = ip + ":8088" } } // проверим, есть ли необработанные ключи в локальной табле nodePrivateKey, err := c.Single("SELECT private_key FROM " + c.MyPrefix + "my_node_keys WHERE block_id = 0").String() if err != nil { return "", utils.ErrInfo(err) } if len(nodePrivateKey) == 0 { // сгенерим ключ для нода priv, pub := utils.GenKeys() err = c.ExecSql("INSERT INTO "+c.MyPrefix+"my_node_keys ( public_key, private_key ) VALUES ( [hex], ? )", pub, priv) if err != nil { return "", utils.ErrInfo(err) } nodePrivateKey = priv } var profileHash, faceHash, videoHash string if _, err := os.Stat(*utils.Dir + "/public/" + utils.Int64ToStr(c.SessUserId) + "_user_face.jpg"); err == nil { file, err := ioutil.ReadFile(*utils.Dir + "/public/" + utils.Int64ToStr(c.SessUserId) + "_user_face.jpg") if err != nil { return "", utils.ErrInfo(err) } faceHash = string(utils.DSha256(file)) } if _, err := os.Stat(*utils.Dir + "/public/" + utils.Int64ToStr(c.SessUserId) + "_user_profile.jpg"); err == nil { file, err := ioutil.ReadFile(*utils.Dir + "/public/" + utils.Int64ToStr(c.SessUserId) + "_user_profile.jpg") if err != nil { return "", utils.ErrInfo(err) } profileHash = string(utils.DSha256(file)) } if _, err := os.Stat(*utils.Dir + "/public/" + utils.Int64ToStr(c.SessUserId) + "_user_video.mp4"); err == nil { file, err := ioutil.ReadFile(*utils.Dir + "/public/" + utils.Int64ToStr(c.SessUserId) + "_user_video.mp4") if err != nil { return "", utils.ErrInfo(err) } videoHash = string(utils.DSha256(file)) } text, err := utils.GetHttpTextAnswer("http://dcoin.club/pools") if err != nil { return "", utils.ErrInfo(err) } var pools_ []string err = json.Unmarshal([]byte(text), &pools_) if err != nil { return "", utils.ErrInfo(err) } log.Debug("pools: %v", pools_) rows, err := c.Query(c.FormatQuery(` SELECT user_id, http_host FROM miners_data WHERE user_id IN (` + strings.Join(pools_, ",") + `)`)) if err != nil { return "", utils.ErrInfo(err) } defer rows.Close() pools := make(map[string]string) for rows.Next() { var user_id, http_host string err = rows.Scan(&user_id, &http_host) if err != nil { return "", utils.ErrInfo(err) } pools[user_id] = http_host } poolsJs := "" for userId, httpHost := range pools { poolsJs = poolsJs + "[" + userId + ",'" + httpHost + "']," } poolsJs = poolsJs[:len(poolsJs)-1] videoUrlId, err := c.Single("SELECT video_url_id FROM " + c.MyPrefix + "my_table").String() if err != nil { return "", utils.ErrInfo(err) } saveAndGotoStep := strings.Replace(c.Lang["save_and_goto_step"], "[num]", "8", -1) upgradeMenu := utils.MakeUpgradeMenu(6) TemplateStr, err := makeTemplate("upgrade_6", "upgrade6", &upgrade6Page{ Alert: c.Alert, Lang: c.Lang, SaveAndGotoStep: saveAndGotoStep, UpgradeMenu: upgradeMenu, ShowSignData: c.ShowSignData, SignData: "", CountSignArr: c.CountSignArr, HttpHost: hostData["http_host"], TcpHost: hostData["tcp_host"], Community: c.Community, HostType: hostType, ProfileHash: profileHash, FaceHash: faceHash, VideoHash: videoHash, NodePrivateKey: nodePrivateKey, Pools: template.JS(poolsJs), UserId: c.SessUserId, VideoUrlId: videoUrlId, Mobile: utils.Mobile()}) if err != nil { return "", utils.ErrInfo(err) } return TemplateStr, nil }
func (c *Controller) Upgrade7() (string, error) { log.Debug("Upgrade7") txType := "NewMiner" txTypeId := utils.TypeInt(txType) timeNow := utils.Time() // Формируем контент для подписи myTable, err := c.OneRow("SELECT user_id, race, country, geolocation, http_host, tcp_host, face_coords, profile_coords, video_url_id, video_type FROM " + c.MyPrefix + "my_table").String() if err != nil { return "", utils.ErrInfo(err) } if len(myTable["video_url_id"]) == 0 { myTable["video_url_id"] = "null" } if len(myTable["video_type"]) == 0 { myTable["video_type"] = "null" } var profileHash, faceHash string if _, err := os.Stat(*utils.Dir + "/public/" + utils.Int64ToStr(c.SessUserId) + "_user_face.jpg"); err == nil { file, err := ioutil.ReadFile(*utils.Dir + "/public/" + utils.Int64ToStr(c.SessUserId) + "_user_face.jpg") if err != nil { return "", utils.ErrInfo(err) } faceHash = string(utils.DSha256(file)) } if _, err := os.Stat(*utils.Dir + "/public/" + utils.Int64ToStr(c.SessUserId) + "_user_profile.jpg"); err == nil { file, err := ioutil.ReadFile(*utils.Dir + "/public/" + utils.Int64ToStr(c.SessUserId) + "_user_profile.jpg") if err != nil { return "", utils.ErrInfo(err) } profileHash = string(utils.DSha256(file)) } latitude := "0" longitude := "0" if len(myTable["geolocation"]) > 0 { x := strings.Split(myTable["geolocation"], ", ") latitude = x[0] longitude = x[1] } // проверим, есть ли не обработанные ключи в локальной табле nodePublicKey, err := c.Single("SELECT public_key FROM " + c.MyPrefix + "my_node_keys WHERE block_id = 0").String() if err != nil { return "", utils.ErrInfo(err) } if len(nodePublicKey) == 0 { // сгенерим ключ для нода priv, pub := utils.GenKeys() err = c.ExecSql("INSERT INTO "+c.MyPrefix+"my_node_keys ( public_key, private_key ) VALUES ( [hex], ? )", pub, priv) if err != nil { return "", utils.ErrInfo(err) } } else { nodePublicKey = string(utils.BinToHex([]byte(nodePublicKey))) } saveAndGotoStep := strings.Replace(c.Lang["save_and_goto_step"], "[num]", "9", -1) upgradeMenu := utils.MakeUpgradeMenu(7) var noExistsMp4 bool if _, err := os.Stat(*utils.Dir + "/public/" + utils.Int64ToStr(c.SessUserId) + "_user_video.mp4"); os.IsNotExist(err) { noExistsMp4 = true } TemplateStr, err := makeTemplate("upgrade_7", "upgrade7", &upgrade7Page{ Alert: c.Alert, Lang: c.Lang, CountSignArr: c.CountSignArr, ShowSignData: c.ShowSignData, UserId: c.SessUserId, TimeNow: timeNow, TxType: txType, TxTypeId: txTypeId, NoExistsMp4: noExistsMp4, SignData: fmt.Sprintf("%v,%v,%v,%v,%v,%v,%v,%v,%v,%v,%v,%v,%v,%v,%v,%v", txTypeId, timeNow, c.SessUserId, myTable["race"], myTable["country"], latitude, longitude, myTable["http_host"], myTable["tcp_host"], faceHash, profileHash, myTable["face_coords"], myTable["profile_coords"], myTable["video_type"], myTable["video_url_id"], nodePublicKey), SaveAndGotoStep: saveAndGotoStep, UpgradeMenu: upgradeMenu, Latitude: latitude, Longitude: longitude, NodePublicKey: nodePublicKey, ProfileHash: profileHash, FaceHash: faceHash, Data: myTable, MyTable: myTable, Mobile: utils.Mobile()}) if err != nil { return "", utils.ErrInfo(err) } return TemplateStr, nil }
func (c *Controller) DcoinKey() (string, error) { var err error c.r.ParseForm() // на IOS/Android запрос ключа идет без сессии из objective C (UIImage *image = [UIImage imageWithData:[NSData dataWithContentsOfURL:[NSURL URLWithString:@"http://127.0.0.1:8089/ajax?controllerName=dcoinKey&ios=1"]]];) local := false // чтобы по локалке никто не украл приватный ключ if ok, _ := regexp.MatchString(`^(\:\:)|(127\.0\.0\.1)(:[0-9]+)?$`, c.r.RemoteAddr); ok { local = true } if utils.Mobile() && c.SessUserId == 0 && !local { return "", utils.ErrInfo(errors.New("Not local request from " + c.r.RemoteAddr)) } privKey := "" if len(c.r.FormValue("first")) > 0 { privKey, err = c.Single(`SELECT private_key FROM ` + c.MyPrefix + `my_keys WHERE status='my_pending'`).String() if err != nil { return "", utils.ErrInfo(err) } } else { privKey, _ = utils.GenKeys() } paramNoPass := utils.ParamType{X: 176, Y: 100, Width: 100, Bg_path: "static/img/k_bg.png"} paramPass := utils.ParamType{X: 167, Y: 93, Width: 118, Bg_path: "static/img/k_bg_pass.png"} var param utils.ParamType var privateKey string if len(c.r.FormValue("password")) > 0 { privateKey_, err := utils.Encrypt(utils.Md5(c.r.FormValue("password")), []byte(privKey)) privateKey = base64.StdEncoding.EncodeToString(privateKey_) if err != nil { return "", utils.ErrInfo(err) } param = paramPass } else { privateKey = strings.Replace(privKey, "-----BEGIN RSA PRIVATE KEY-----", "", -1) privateKey = strings.Replace(privateKey, "-----END RSA PRIVATE KEY-----", "", -1) param = paramNoPass } ios := false if ok, _ := regexp.MatchString("(iPod|iPhone|iPad)", c.r.UserAgent()); ok { ios = true } if len(c.r.FormValue("ios")) > 0 { ios = true } if ios || utils.Android() { buffer, err := utils.KeyToImg(privateKey, "", c.SessUserId, c.TimeFormat, param) if err != nil { return "", utils.ErrInfo(err) } c.w.Header().Set("Content-Type", "image/png") c.w.Header().Set("Content-Length", utils.IntToStr(len(buffer.Bytes()))) c.w.Header().Set("Content-Disposition", `attachment; filename="Dcoin-private-key-`+utils.Int64ToStr(c.SessUserId)+`.png"`) if _, err := c.w.Write(buffer.Bytes()); err != nil { return "", utils.ErrInfo(errors.New("unable to write image")) } } else { c.w.Header().Set("Content-Type", "text/plain") c.w.Header().Set("Content-Length", utils.IntToStr(len(privateKey))) c.w.Header().Set("Content-Disposition", `attachment; filename="Dcoin-private-key-`+utils.Int64ToStr(c.SessUserId)+`.txt"`) if _, err := c.w.Write([]byte(privateKey)); err != nil { return "", utils.ErrInfo(errors.New("unable to write text")) } } return "", nil }