407 lines
11 KiB
Go
407 lines
11 KiB
Go
|
|
package main
|
||
|
|
|
||
|
|
import (
|
||
|
|
"database/sql"
|
||
|
|
"fmt"
|
||
|
|
"html/template"
|
||
|
|
"log"
|
||
|
|
"net/http"
|
||
|
|
"os"
|
||
|
|
"os/exec"
|
||
|
|
"strings"
|
||
|
|
"time"
|
||
|
|
_ "github.com/mattn/go-sqlite3"
|
||
|
|
"context"
|
||
|
|
"io/ioutil"
|
||
|
|
"github.com/chromedp/chromedp"
|
||
|
|
"crypto/md5"
|
||
|
|
"encoding/hex"
|
||
|
|
)
|
||
|
|
|
||
|
|
// Start Web PART
|
||
|
|
type urlinfo struct {
|
||
|
|
Date string
|
||
|
|
Url string
|
||
|
|
Description string
|
||
|
|
Tags string
|
||
|
|
Screenshot string
|
||
|
|
Separated []string
|
||
|
|
Duplicated []string
|
||
|
|
}
|
||
|
|
|
||
|
|
type Message struct {
|
||
|
|
Msj string
|
||
|
|
}
|
||
|
|
|
||
|
|
func main() {
|
||
|
|
var filedb string
|
||
|
|
var homepath = os.Getenv("HOME")
|
||
|
|
if os.Getenv("babil0nia_DB") == "" {
|
||
|
|
filedb = homepath+"/babil0nia.db"
|
||
|
|
} else {
|
||
|
|
filedb = os.Getenv("babil0nia_DB")
|
||
|
|
}
|
||
|
|
// Create ~/.babil0niafiles folder to save screenshots
|
||
|
|
if _, err := os.Stat(homepath+"/.babil0niafiles"); os.IsNotExist(err) {
|
||
|
|
err = os.Mkdir(homepath+"/.babil0niafiles", 0755)
|
||
|
|
if err != nil {
|
||
|
|
log.Fatal(err)
|
||
|
|
}
|
||
|
|
}
|
||
|
|
// Link ~/.babil0niafiles to screenshots/ folder.
|
||
|
|
if _, err := os.Stat("screenshots"); os.IsNotExist(err) {
|
||
|
|
cmd := exec.Command("/usr/bin/ln", "-s", homepath+"/.babil0niafiles", "screenshots")
|
||
|
|
_, err := cmd.Output()
|
||
|
|
if err != nil {
|
||
|
|
log.Fatal(err)
|
||
|
|
}
|
||
|
|
}
|
||
|
|
checkDB(filedb)
|
||
|
|
sqliteDatabase, _ := sql.Open("sqlite3", filedb)
|
||
|
|
defer sqliteDatabase.Close()
|
||
|
|
startServer(sqliteDatabase)
|
||
|
|
}
|
||
|
|
|
||
|
|
// Func to check if DB exists, if not create it.
|
||
|
|
func checkDB(filedb string) {
|
||
|
|
_, err := os.Stat(filedb)
|
||
|
|
//If file htask.db doesnt exist.
|
||
|
|
if err != nil {
|
||
|
|
fmt.Println("[+]Creating Database\n")
|
||
|
|
file, err := os.Create(filedb)
|
||
|
|
if err != nil {
|
||
|
|
log.Fatal(err.Error())
|
||
|
|
}
|
||
|
|
file.Close()
|
||
|
|
sqlDB, _ := sql.Open("sqlite3",filedb)
|
||
|
|
defer sqlDB.Close()
|
||
|
|
createTable(sqlDB)
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
// Func to create DB.
|
||
|
|
func createTable(db *sql.DB) {
|
||
|
|
createbabil0niatable := `CREATE TABLE babil0nia (
|
||
|
|
"id" INTEGER PRIMARY KEY AUTOINCREMENT,
|
||
|
|
"date" TEXT,
|
||
|
|
"url" TEXT,
|
||
|
|
"description" TEXT,
|
||
|
|
"tags" TEXT,
|
||
|
|
"screenshot" TEXT
|
||
|
|
);`
|
||
|
|
statement, err := db.Prepare(createbabil0niatable)
|
||
|
|
if err != nil {
|
||
|
|
log.Fatal(err.Error())
|
||
|
|
}
|
||
|
|
statement.Exec()
|
||
|
|
log.Println("[+] babil0nia table created")
|
||
|
|
}
|
||
|
|
|
||
|
|
func startServer(db *sql.DB) {
|
||
|
|
// All requests to /screenshots/ will serve the static content of screenshots/
|
||
|
|
fs := http.FileServer(http.Dir("./screenshots"))
|
||
|
|
http.Handle("/screenshots/", http.StripPrefix("/screenshots/", fs))
|
||
|
|
|
||
|
|
http.HandleFunc("/", babil0niaHandler(db))
|
||
|
|
// All requests to /styles/css will serve static/css/bootstrap.min.css.
|
||
|
|
http.HandleFunc("/styles/css", func(response http.ResponseWriter, request *http.Request) {
|
||
|
|
http.ServeFile(response, request, "static/css/bootstrap.min.css")
|
||
|
|
})
|
||
|
|
|
||
|
|
http.HandleFunc("/add", func(response http.ResponseWriter, request *http.Request) {
|
||
|
|
http.ServeFile(response, request, "static/html/add.html")
|
||
|
|
})
|
||
|
|
|
||
|
|
http.ListenAndServe("127.0.0.1:8002", nil)
|
||
|
|
}
|
||
|
|
|
||
|
|
func babil0niaHandler(db *sql.DB) http.HandlerFunc {
|
||
|
|
return func(w http.ResponseWriter, r *http.Request) {
|
||
|
|
enabled := len(os.Args)
|
||
|
|
var repetido int
|
||
|
|
tagtose := r.URL.Query()["tags"]
|
||
|
|
tagtosearch := strings.Join(tagtose ," ")
|
||
|
|
wordtose := r.URL.Query()["wordtosearch"]
|
||
|
|
wordtosearch := strings.Join(wordtose," ")
|
||
|
|
urltoa := r.URL.Query()["url"]
|
||
|
|
urltoadd := strings.Join(urltoa, " ")
|
||
|
|
descript := r.URL.Query()["description"]
|
||
|
|
descriptoinsert := strings.Join(descript," ")
|
||
|
|
repetido = dupURL(db,urltoadd)
|
||
|
|
urltodel := r.URL.Query()["delete"]
|
||
|
|
urltodelete := strings.Join(urltodel ," ")
|
||
|
|
urltoar := r.URL.Query()["archive"]
|
||
|
|
urltoarchive := strings.Join(urltoar ," ")
|
||
|
|
existeurl := dupURL(db,urltoarchive)
|
||
|
|
existdownload := checkDownload(db,urltoarchive)
|
||
|
|
|
||
|
|
if urltoarchive != "" && enabled > 1 && os.Args[1] == "-a" && existeurl != 0 && existdownload == ""{
|
||
|
|
var homepath = os.Getenv("HOME")
|
||
|
|
filename := getFilename(urltoarchive)
|
||
|
|
screenshotname := filename+".jpg"
|
||
|
|
screenshotfullpath := homepath+"/.babil0niafiles/"+filename+".jpg"
|
||
|
|
|
||
|
|
err, filename := archiveURL(db,urltoarchive,screenshotfullpath,w)
|
||
|
|
if err != nil {
|
||
|
|
fmt.Printf("ERROR UPDATING")
|
||
|
|
} else {
|
||
|
|
updateUrl(db,screenshotname,urltoarchive)
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
if urltoarchive != "" && enabled < 2 || urltoarchive != "" && enabled > 1 && os.Args[1] != "-a" {
|
||
|
|
m := Message{"Archive is disabled."}
|
||
|
|
printMessage(w,m)
|
||
|
|
}
|
||
|
|
|
||
|
|
if urltodelete != "" {
|
||
|
|
imageURLname := getImageName(db,urltodelete)
|
||
|
|
filetodelete := "screenshots/"+imageURLname
|
||
|
|
os.Remove(filetodelete)
|
||
|
|
deleteUrl(db,urltodelete)
|
||
|
|
}
|
||
|
|
|
||
|
|
if urltoadd == "" && descriptoinsert == "" {
|
||
|
|
displaybabil0nia(db, w,tagtosearch,wordtosearch)
|
||
|
|
} else {
|
||
|
|
if repetido != 0 {
|
||
|
|
m := Message{"URL is duplicated."}
|
||
|
|
printMessage(w,m)
|
||
|
|
} else {
|
||
|
|
insertUrl(db,urltoadd,descriptoinsert,tagtosearch)
|
||
|
|
m := Message{"URL added successfully."}
|
||
|
|
printMessage(w,m)
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
func displaybabil0nia(db *sql.DB, w http.ResponseWriter,tagtosearch string, wordtosearch string) {
|
||
|
|
var Arrayurlinfo []urlinfo
|
||
|
|
var Repetidos []string
|
||
|
|
tmpl := template.Must(template.ParseFiles("static/html/main.html"))
|
||
|
|
p := urlinfo{}
|
||
|
|
if tagtosearch == "" && wordtosearch == "" {
|
||
|
|
row, err := db.Query("SELECT date,url,description,tags,screenshot FROM babil0nia")
|
||
|
|
if err != nil {
|
||
|
|
log.Fatal(err)
|
||
|
|
}
|
||
|
|
defer row.Close()
|
||
|
|
for row.Next() {
|
||
|
|
var date string
|
||
|
|
var url string
|
||
|
|
var description string
|
||
|
|
var tags string
|
||
|
|
var screenshot string
|
||
|
|
row.Scan( &date, &url, &description, &tags, &screenshot)
|
||
|
|
// s is []string where tags are separated by ,
|
||
|
|
s := strings.Split(tags, ",")
|
||
|
|
//All s elementes are appended to Repetidos []string
|
||
|
|
for _,element := range s {
|
||
|
|
Repetidos = append(Repetidos,element)
|
||
|
|
}
|
||
|
|
p = urlinfo{date,url,description,tags,screenshot,s,nil}
|
||
|
|
Arrayurlinfo = append(Arrayurlinfo, p)
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
if tagtosearch != "" && wordtosearch == "" {
|
||
|
|
row, err := db.Query("SELECT date,url,description,tags,screenshot FROM babil0nia where tags like ?","%"+tagtosearch+"%")
|
||
|
|
if err != nil {
|
||
|
|
log.Fatal(err)
|
||
|
|
}
|
||
|
|
defer row.Close()
|
||
|
|
for row.Next() {
|
||
|
|
var date string
|
||
|
|
var url string
|
||
|
|
var description string
|
||
|
|
var tags string
|
||
|
|
var screenshot string
|
||
|
|
row.Scan( &date, &url, &description, &tags, &screenshot)
|
||
|
|
var s []string
|
||
|
|
s = strings.Split(tags, ",")
|
||
|
|
for _,element := range s {
|
||
|
|
Repetidos = append(Repetidos,element)
|
||
|
|
}
|
||
|
|
p = urlinfo{date,url,description,tags,screenshot,s,nil}
|
||
|
|
Arrayurlinfo = append(Arrayurlinfo, p)
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
if tagtosearch == "" && wordtosearch != "" {
|
||
|
|
row, err := db.Query("SELECT date,url,description,tags,screenshot FROM babil0nia where url like ? or description like ?","%"+wordtosearch+"%","%"+wordtosearch+"%")
|
||
|
|
if err != nil {
|
||
|
|
log.Fatal(err)
|
||
|
|
}
|
||
|
|
defer row.Close()
|
||
|
|
for row.Next() {
|
||
|
|
var date string
|
||
|
|
var url string
|
||
|
|
var description string
|
||
|
|
var tags string
|
||
|
|
var screenshot string
|
||
|
|
row.Scan( &date, &url, &description, &tags, &screenshot)
|
||
|
|
var s []string
|
||
|
|
s = strings.Split(tags, ",")
|
||
|
|
for _,element := range s {
|
||
|
|
Repetidos = append(Repetidos,element)
|
||
|
|
}
|
||
|
|
p = urlinfo{date,url,description,tags,screenshot,s,nil}
|
||
|
|
Arrayurlinfo = append(Arrayurlinfo, p)
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
//Repetidos store now []string without tags duplicated.
|
||
|
|
Repetidos = removeDuplicates(Repetidos)
|
||
|
|
// Creates the last urlinfo struct with Repetidos.
|
||
|
|
lastp := urlinfo{"","","","","",nil,Repetidos}
|
||
|
|
Arrayurlinfo = append(Arrayurlinfo,lastp)
|
||
|
|
tmpl.Execute(w,Arrayurlinfo)
|
||
|
|
}
|
||
|
|
|
||
|
|
// Func to Print Messages through Web.
|
||
|
|
func printMessage(w http.ResponseWriter, msg Message) {
|
||
|
|
tmpl := template.Must(template.ParseFiles("static/html/message.html"))
|
||
|
|
tmpl.Execute(w, msg)
|
||
|
|
}
|
||
|
|
|
||
|
|
// Inserting URL into SQL.
|
||
|
|
func insertUrl(db *sql.DB, url string, descriptoinsert string, tagstoinsert string) {
|
||
|
|
currentTime := time.Now()
|
||
|
|
date := currentTime.Format("01-02-2006")
|
||
|
|
insertURLSQL := `INSERT INTO babil0nia(date,url,description,tags) VALUES (?,?,?,?)`
|
||
|
|
statement, err := db.Prepare(insertURLSQL)
|
||
|
|
if err != nil {
|
||
|
|
log.Fatalln(err.Error())
|
||
|
|
}
|
||
|
|
_, err = statement.Exec(date, url,descriptoinsert, tagstoinsert)
|
||
|
|
if err != nil {
|
||
|
|
log.Fatalln(err.Error())
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
// Delete URL.
|
||
|
|
func deleteUrl(db *sql.DB, url string) {
|
||
|
|
deleteURLSQL := `DELETE FROM babil0nia WHERE url = ?`
|
||
|
|
statement, err := db.Prepare(deleteURLSQL)
|
||
|
|
if err != nil {
|
||
|
|
log.Fatalln(err.Error())
|
||
|
|
}
|
||
|
|
_, err = statement.Exec(url)
|
||
|
|
if err != nil {
|
||
|
|
log.Fatalln(err.Error())
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
// Func to update an URL to add the filename of the screenshot.
|
||
|
|
func updateUrl(db *sql.DB, filename string, url string) {
|
||
|
|
updateURLSQL := `UPDATE babil0nia set screenshot = ? WHERE url = ?`
|
||
|
|
statement, err := db.Prepare(updateURLSQL)
|
||
|
|
if err != nil {
|
||
|
|
log.Fatalln(err.Error())
|
||
|
|
}
|
||
|
|
_, err = statement.Exec(filename,url)
|
||
|
|
if err != nil {
|
||
|
|
log.Fatalln(err.Error())
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
// Func to check if URL is duplicated, it returns an int with the number of times that URL is repeated.
|
||
|
|
func dupURL(db *sql.DB, url string) int{
|
||
|
|
var total int
|
||
|
|
row, err := db.Query("SELECT count(*) as total from babil0nia where url = ?",url)
|
||
|
|
if err != nil {
|
||
|
|
log.Fatal(err)
|
||
|
|
}
|
||
|
|
defer row.Close()
|
||
|
|
for row.Next() {
|
||
|
|
var count int
|
||
|
|
row.Scan( &count)
|
||
|
|
total = count
|
||
|
|
}
|
||
|
|
return total
|
||
|
|
}
|
||
|
|
|
||
|
|
// Func to check if URL has the file downloaded.
|
||
|
|
func checkDownload(db *sql.DB, url string) string{
|
||
|
|
var total string
|
||
|
|
row, err := db.Query("SELECT screenshot from babil0nia where url = ?",url)
|
||
|
|
if err != nil {
|
||
|
|
log.Fatal(err)
|
||
|
|
}
|
||
|
|
defer row.Close()
|
||
|
|
for row.Next() {
|
||
|
|
var screenshot string
|
||
|
|
row.Scan( &screenshot)
|
||
|
|
total = screenshot
|
||
|
|
}
|
||
|
|
return total
|
||
|
|
}
|
||
|
|
|
||
|
|
// Func to get the "id" that will be used as imagename from an given URL, it returns the id.
|
||
|
|
func getImageName(db *sql.DB, url string) string{
|
||
|
|
var imagename string
|
||
|
|
row, err := db.Query("SELECT screenshot from babil0nia where url = ?",url)
|
||
|
|
if err != nil {
|
||
|
|
log.Fatal(err)
|
||
|
|
}
|
||
|
|
defer row.Close()
|
||
|
|
for row.Next() {
|
||
|
|
var screenshot string
|
||
|
|
row.Scan( &screenshot)
|
||
|
|
imagename = screenshot
|
||
|
|
}
|
||
|
|
return imagename
|
||
|
|
}
|
||
|
|
|
||
|
|
// Func to remove duplicated strings from an slice.
|
||
|
|
func removeDuplicates(strSlice []string) []string {
|
||
|
|
allKeys := make(map[string]bool)
|
||
|
|
list := []string{}
|
||
|
|
for _, item := range strSlice {
|
||
|
|
if _, value := allKeys[item]; !value {
|
||
|
|
allKeys[item] = true
|
||
|
|
list = append(list, item)
|
||
|
|
}
|
||
|
|
}
|
||
|
|
return list
|
||
|
|
}
|
||
|
|
|
||
|
|
// Func to create a filename using the md5 hash of the url name.
|
||
|
|
func getFilename(text string) string {
|
||
|
|
hash := md5.Sum([]byte(text))
|
||
|
|
return hex.EncodeToString(hash[:])
|
||
|
|
}
|
||
|
|
|
||
|
|
// Func to take one screenshot from the given URL and save it to a file. It returns error and the name of the saved (screenshot) file.
|
||
|
|
func archiveURL(db *sql.DB,urltoarchive string, filename string,w http.ResponseWriter) (error,string){
|
||
|
|
var fail error
|
||
|
|
ctx, cancel := chromedp.NewContext(
|
||
|
|
context.Background(),
|
||
|
|
)
|
||
|
|
defer cancel()
|
||
|
|
var buf []byte
|
||
|
|
if err := chromedp.Run(ctx, fullScreenshot(urltoarchive, 100, &buf)); err != nil {
|
||
|
|
m := Message{"Error downloading."}
|
||
|
|
printMessage(w,m)
|
||
|
|
fail = err
|
||
|
|
}
|
||
|
|
if fail != nil {
|
||
|
|
fmt.Println("Fallo la descarga de la imagen asi que nos e guarda")
|
||
|
|
} else {
|
||
|
|
if err := ioutil.WriteFile(filename, buf, 0o644); err != nil {
|
||
|
|
m := Message{"Error saving the image."}
|
||
|
|
printMessage(w,m)
|
||
|
|
fail = err
|
||
|
|
}
|
||
|
|
}
|
||
|
|
return fail, filename
|
||
|
|
}
|
||
|
|
|
||
|
|
func fullScreenshot(urlstr string, quality int, res *[]byte) chromedp.Tasks {
|
||
|
|
return chromedp.Tasks{
|
||
|
|
chromedp.Navigate(urlstr),
|
||
|
|
chromedp.FullScreenshot(res, quality),
|
||
|
|
}
|
||
|
|
}
|