2023-05-12 14:18:37 +09:00
|
|
|
package main
|
|
|
|
|
|
|
|
import (
|
|
|
|
"os"
|
|
|
|
"fmt"
|
|
|
|
"strings"
|
|
|
|
"net/http"
|
2023-06-23 12:48:13 +09:00
|
|
|
"net/url"
|
2023-05-12 14:18:37 +09:00
|
|
|
"io"
|
|
|
|
"regexp"
|
2023-05-12 16:34:02 +09:00
|
|
|
"errors"
|
2023-06-23 12:48:13 +09:00
|
|
|
"path/filepath"
|
2023-05-12 14:18:37 +09:00
|
|
|
)
|
|
|
|
|
2023-05-12 16:34:02 +09:00
|
|
|
func scanpage (path string, domain string, thisdomain string) error {
|
2023-06-27 13:48:35 +09:00
|
|
|
// 先に保存したページを読み込む
|
2023-05-12 14:18:37 +09:00
|
|
|
fn, err := os.ReadFile(path + "/index.html")
|
|
|
|
if err != nil {
|
2023-06-23 12:48:13 +09:00
|
|
|
return err
|
2023-05-12 14:18:37 +09:00
|
|
|
}
|
|
|
|
|
2023-06-27 13:48:35 +09:00
|
|
|
// 要らないタグを削除
|
2023-05-12 14:18:37 +09:00
|
|
|
var script = regexp.MustCompile(`(<script.*</script>)`).ReplaceAllString(string(fn), "")
|
|
|
|
var noscript = regexp.MustCompile(`(<noscript.*</noscript>)`).ReplaceAllString(string(script), "")
|
|
|
|
var audio = regexp.MustCompile(`(<audio.*</audio>)`).ReplaceAllString(string(noscript), "")
|
|
|
|
var video = regexp.MustCompile(`(<video.*</video>)`).ReplaceAllString(string(audio), "")
|
|
|
|
var iframe = regexp.MustCompile(`(<iframe.*</iframe>)`).ReplaceAllString(string(video), "")
|
2023-06-27 13:48:35 +09:00
|
|
|
// 追加ダウンロード+ローカル化
|
2023-06-23 18:09:23 +09:00
|
|
|
var ass = regexp.MustCompile(`(<img.*src=['"]|<meta.*content=['"]|<link.*href=['"])(.*\.)(png|webp|jpg|jpeg|gif|css|js|ico|svg|ttf|woff2)(\?[^'"]*)?`)
|
2023-06-23 12:48:13 +09:00
|
|
|
|
2023-06-27 13:48:35 +09:00
|
|
|
// 必要であれば、ページ内のURLを修正
|
2023-05-12 16:34:02 +09:00
|
|
|
spath := "static/"
|
|
|
|
if !strings.HasSuffix(path, "/") {
|
|
|
|
spath = "/" + spath
|
|
|
|
}
|
|
|
|
spath = path + spath
|
2023-06-27 13:48:35 +09:00
|
|
|
|
|
|
|
// また、追加ダウンロードのファイルに上記のフォルダを創作
|
2023-06-23 12:48:13 +09:00
|
|
|
err = os.Mkdir(spath, 0755)
|
|
|
|
if err != nil {
|
|
|
|
return err
|
2023-05-12 16:34:02 +09:00
|
|
|
}
|
2023-05-12 14:18:37 +09:00
|
|
|
|
2023-06-23 12:48:13 +09:00
|
|
|
repmap := make(map[string]string)
|
|
|
|
|
2023-05-12 14:18:37 +09:00
|
|
|
for _, cssx := range ass.FindAllString(iframe, -1) {
|
2023-06-27 13:48:35 +09:00
|
|
|
// ページ内のURLを受け取る
|
2023-06-23 12:48:13 +09:00
|
|
|
s := regexp.MustCompile(`(.*src=['"]|.*content=['"]|.*href=['"])`).Split(cssx, -1)
|
|
|
|
ss := regexp.MustCompile(`(['"].*)`).Split(s[1], -1)
|
|
|
|
|
2023-06-27 13:48:35 +09:00
|
|
|
ogurl := ss[0] // 変わる前に元のURLを保存して
|
|
|
|
// URLは//で始まるは愛
|
2023-06-23 12:48:13 +09:00
|
|
|
if strings.HasPrefix(ss[0], "//") {
|
|
|
|
ss[0] = "https:" + ss[0]
|
|
|
|
}
|
|
|
|
|
2023-06-27 13:48:35 +09:00
|
|
|
// ファイル名を見つけて
|
2023-06-23 12:48:13 +09:00
|
|
|
fss := strings.Split(ss[0], "/")
|
|
|
|
assdom := ""
|
|
|
|
filename := fss[len(fss)-1]
|
|
|
|
|
2023-06-27 13:48:35 +09:00
|
|
|
// httpかhttpsで始まる場合
|
2023-05-12 14:18:37 +09:00
|
|
|
if strings.HasPrefix(ss[0], "http://") || strings.HasPrefix(ss[0], "https://") {
|
2023-06-23 12:48:13 +09:00
|
|
|
assdom = fss[2]
|
|
|
|
}
|
2023-05-12 14:18:37 +09:00
|
|
|
|
2023-06-27 13:48:35 +09:00
|
|
|
// フォルダの創作
|
2023-06-23 12:48:13 +09:00
|
|
|
asspath := path + "/static/" + assdom
|
|
|
|
err = os.MkdirAll(asspath, 0755)
|
2023-06-27 13:48:35 +09:00
|
|
|
if err != nil { // 出来なければ、死ね
|
2023-06-23 12:48:13 +09:00
|
|
|
return err
|
|
|
|
}
|
2023-05-12 14:18:37 +09:00
|
|
|
|
2023-06-27 13:48:35 +09:00
|
|
|
if filename == "" { // ファイル名がなければ、次に値にスキップしてね
|
2023-06-23 12:48:13 +09:00
|
|
|
continue
|
|
|
|
}
|
|
|
|
|
2023-06-27 13:48:35 +09:00
|
|
|
if strings.HasPrefix(ss[0], "http://") || strings.HasPrefix(ss[0], "https://") { // httpかhttpsで始まったら、ダウンロードだけしよう
|
2023-06-23 12:48:13 +09:00
|
|
|
err = dlres(ss[0], filepath.Join(asspath, filename))
|
2023-06-27 13:48:35 +09:00
|
|
|
if err != nil { // 出来なければ、死ね
|
2023-06-23 12:48:13 +09:00
|
|
|
return err
|
2023-05-12 14:18:37 +09:00
|
|
|
}
|
2023-06-27 13:48:35 +09:00
|
|
|
} else { // ローカルファイルなら、ちょっと変更は必要となるかしら
|
2023-06-23 18:09:23 +09:00
|
|
|
u, err := url.Parse(domain)
|
2023-06-27 13:48:35 +09:00
|
|
|
if err != nil { // 出来なければ、死ね
|
2023-06-23 18:09:23 +09:00
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
|
|
|
rel, err := url.Parse(ss[0])
|
2023-06-27 13:48:35 +09:00
|
|
|
if err != nil { // 出来なければ、死ね
|
2023-06-23 18:09:23 +09:00
|
|
|
return err
|
2023-05-12 14:18:37 +09:00
|
|
|
}
|
2023-06-23 18:09:23 +09:00
|
|
|
|
|
|
|
af := u.ResolveReference(rel).String()
|
|
|
|
|
2023-06-23 12:48:13 +09:00
|
|
|
err = dlres(af, filepath.Join(asspath, filename))
|
2023-06-27 13:48:35 +09:00
|
|
|
if err != nil { // 出来なければ、死ね
|
2023-06-23 12:48:13 +09:00
|
|
|
return err
|
|
|
|
}
|
|
|
|
}
|
2023-05-12 14:18:37 +09:00
|
|
|
|
2023-06-23 18:09:23 +09:00
|
|
|
repmap[ogurl] = filepath.Join("/static", assdom, filename)
|
2023-06-23 12:48:13 +09:00
|
|
|
if assdom == "" {
|
2023-06-23 18:09:23 +09:00
|
|
|
repmap[ogurl] = filepath.Join("/static", filename)
|
2023-05-12 14:18:37 +09:00
|
|
|
}
|
|
|
|
|
2023-06-27 13:48:35 +09:00
|
|
|
if err != nil { // 出来なければ、死ね
|
2023-05-12 16:34:02 +09:00
|
|
|
fmt.Println(err)
|
2023-06-27 13:48:35 +09:00
|
|
|
return errors.New("ダウンロードに失敗:")
|
2023-06-23 12:48:13 +09:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-06-27 13:48:35 +09:00
|
|
|
// URLをローカル化
|
2023-06-23 12:48:13 +09:00
|
|
|
for ourl, lurl := range repmap {
|
|
|
|
aurl := strings.ReplaceAll(path, thisdomain, "") + stripver(lurl)
|
|
|
|
iframe = strings.ReplaceAll(iframe, ourl, aurl)
|
|
|
|
}
|
|
|
|
|
2023-06-27 13:48:35 +09:00
|
|
|
// index.htmlファイルを更新する
|
2023-06-23 12:48:13 +09:00
|
|
|
err = os.WriteFile(path + "/index.html", []byte(iframe), 0644)
|
2023-06-27 13:48:35 +09:00
|
|
|
if err != nil { // 出来なければ、死ね
|
2023-06-23 12:48:13 +09:00
|
|
|
fmt.Println(err)
|
|
|
|
return errors.New("書込に失敗")
|
|
|
|
}
|
|
|
|
|
2023-06-27 13:48:35 +09:00
|
|
|
return nil // エラーが出なかったから、返すのは不要
|
2023-06-23 12:48:13 +09:00
|
|
|
}
|
|
|
|
|
2023-06-27 13:48:35 +09:00
|
|
|
// 画像、JS、CSS等ファイルのURLでパラメートルがある場合
|
2023-06-23 12:48:13 +09:00
|
|
|
func stripver (durl string) string {
|
|
|
|
u, err := url.Parse(durl)
|
|
|
|
if err != nil {
|
|
|
|
fmt.Println("エラー:", err)
|
|
|
|
return ""
|
|
|
|
}
|
2023-06-23 18:09:23 +09:00
|
|
|
|
2023-06-23 12:48:13 +09:00
|
|
|
u.RawQuery = ""
|
|
|
|
return u.Path
|
|
|
|
}
|
|
|
|
|
|
|
|
func dlres (durl string, dest string) error {
|
|
|
|
// ダウンロード
|
2023-06-23 18:09:23 +09:00
|
|
|
res, err := http.Get(durl)
|
2023-06-23 12:48:13 +09:00
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
defer res.Body.Close()
|
|
|
|
|
2023-06-27 13:48:35 +09:00
|
|
|
dest = stripver(dest) // URLでパラメートルがあれば、消す
|
2023-06-23 12:48:13 +09:00
|
|
|
|
2023-06-23 18:09:23 +09:00
|
|
|
// MIMEタイプを確認
|
|
|
|
ct := res.Header.Get("Content-Type")
|
|
|
|
for mime, ext := range getmime() {
|
|
|
|
if strings.Contains(ct, mime) && !strings.HasSuffix(dest, ext) {
|
|
|
|
dest += ext
|
|
|
|
break
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-06-23 12:48:13 +09:00
|
|
|
// ファイルを作成
|
|
|
|
f, err := os.Create(dest)
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
defer f.Close()
|
|
|
|
|
|
|
|
// ファイルを書き込む
|
2023-06-23 18:09:23 +09:00
|
|
|
_, err = io.Copy(f, res.Body)
|
|
|
|
if err != nil {
|
|
|
|
return err
|
2023-05-12 14:18:37 +09:00
|
|
|
}
|
2023-05-12 16:34:02 +09:00
|
|
|
|
|
|
|
return nil
|
2023-05-12 14:18:37 +09:00
|
|
|
}
|