Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

opencart4 support #13

Merged
merged 8 commits into from
Feb 9, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
25 changes: 25 additions & 0 deletions .github/workflows/lint.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
name: Lint

on:
pull_request:
branches:
- main

permissions:
contents: read
pull-requests: read

jobs:
lint:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- uses: actions/setup-go@v4
with:
go-version: '1.20'
cache: false
- name: Lint
uses: golangci/golangci-lint-action@v3
with:
version: latest
only-new-issues: true
27 changes: 27 additions & 0 deletions cmd/find/find.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
package main

import (
"fmt"
"log"
"os"

"github.com/sansecio/gocommerce"
)

func main() {
if len(os.Args) <= 1 {
log.Fatalln("No document root specified.")
}

store := gocommerce.FindStoreAtRoot(os.Args[1])
if store == nil {
log.Fatalf("Unable to find store at %s\n", os.Args[1])
}

ver, err := store.Platform.Version(os.Args[1])
if err != nil {
ver = "unknown"
}
fmt.Printf("Found %s (ver: %s) at %s\n", store.Platform.Name(), ver, os.Args[1])
fmt.Printf("DBC: %+v\n", store.Config.DB)
}
20 changes: 20 additions & 0 deletions fixture/opencart4/admin/index.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
<?php
// Version
define('VERSION', '4.0.2.3');

// Configuration
if (is_file('config.php')) {
require_once('config.php');
}

// Installs
if (!defined('DIR_APPLICATION')) {
header('Location: ../install/index.php');
exit();
}

// Startup
require_once(DIR_SYSTEM . 'startup.php');

// Framework
require_once(DIR_SYSTEM . 'framework.php');
31 changes: 31 additions & 0 deletions fixture/opencart4/config.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
<?php
// APPLICATION
define('APPLICATION', 'Catalog');

// HTTP
define('HTTP_SERVER', 'http://sansec.io/');

// DIR
define('DIR_OPENCART', '/home/sansec/Code/opencart/');
define('DIR_APPLICATION', DIR_OPENCART . 'catalog/');
define('DIR_EXTENSION', DIR_OPENCART . 'extension/');
define('DIR_IMAGE', DIR_OPENCART . 'image/');
define('DIR_SYSTEM', DIR_OPENCART . 'system/');
define('DIR_STORAGE', '/home/sansec/Code/storage/');
define('DIR_LANGUAGE', DIR_APPLICATION . 'language/');
define('DIR_TEMPLATE', DIR_APPLICATION . 'view/template/');
define('DIR_CONFIG', DIR_SYSTEM . 'config/');
define('DIR_CACHE', DIR_STORAGE . 'cache/');
define('DIR_DOWNLOAD', DIR_STORAGE . 'download/');
define('DIR_LOGS', DIR_STORAGE . 'logs/');
define('DIR_SESSION', DIR_STORAGE . 'session/');
define('DIR_UPLOAD', DIR_STORAGE . 'upload/');

// DB
define('DB_DRIVER', 'mysqli');
define('DB_HOSTNAME', 'localhost');
define('DB_USERNAME', 'root');
define('DB_PASSWORD', 'root');
define('DB_DATABASE', 'opencart');
define('DB_PORT', '3306');
define('DB_PREFIX', 'oc_');
5 changes: 5 additions & 0 deletions magento1.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,11 @@ import (
"gopkg.in/xmlpath.v2"
)

type Magento1 struct {
basePlatform
Magerun string
}

const (
versionRegex = "(?m)public static function getVersionInfo[^=]+=>\\s'(\\d)',[^=]+=>\\s'(\\d)',[^=]+=>\\s'(\\d)',[^=]+=>\\s'(\\d)',"
)
Expand Down
11 changes: 6 additions & 5 deletions magento1_config_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,10 +6,9 @@ import (
"github.com/stretchr/testify/assert"
)

var magento1 = Magento1{}

func TestParseConfigSimpleMagento1DB(t *testing.T) {
dbc := dbConfigFromSource(t, fixtureBase+"/magento1/app/etc/local.xml", &magento1)
m1 := Magento1{}
dbc := dbConfigFromSource(t, fixtureBase+"/magento1/app/etc/local.xml", &m1)

assert.Equal(t, "localhost", dbc.Host)
assert.Equal(t, "mag1", dbc.Name)
Expand All @@ -20,13 +19,15 @@ func TestParseConfigSimpleMagento1DB(t *testing.T) {
}

func TestParseConfigHostWithPort(t *testing.T) {
dbc := dbConfigFromSource(t, fixtureBase+"/magento1/configs/app/etc/local.xml.hostport", &magento1)
m1 := Magento1{}
dbc := dbConfigFromSource(t, fixtureBase+"/magento1/configs/app/etc/local.xml.hostport", &m1)
assert.Equal(t, "localhost", dbc.Host)
assert.Equal(t, 3307, dbc.Port)
}

func TestParseEmptyPassword(t *testing.T) {
dbc := dbConfigFromSource(t, fixtureBase+"/magento1/configs/app/etc/local.xml.nopass", &magento1)
m1 := Magento1{}
dbc := dbConfigFromSource(t, fixtureBase+"/magento1/configs/app/etc/local.xml.nopass", &m1)
assert.Equal(t, "jeroen:@tcp(db:3306)/jeroen_schweigmann?allowOldPasswords=true", dbc.DSN())
}

Expand Down
5 changes: 5 additions & 0 deletions magento2.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,11 @@ import (
)

type (
Magento2 struct {
basePlatform
Magerun string
}

composerRoot struct {
Name string `json:"name"`
Version string `json:"version"`
Expand Down
29 changes: 18 additions & 11 deletions magento2_config_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,10 +6,9 @@ import (
"github.com/stretchr/testify/assert"
)

var magento2 = Magento2{}

func TestParseConfigMultiDB(t *testing.T) {
dbc := dbConfigFromSource(t, fixtureBase+"/magento2/configs/multidb.php", &magento2)
m2 := Magento2{}
dbc := dbConfigFromSource(t, fixtureBase+"/magento2/configs/multidb.php", &m2)
assert.Equal(t, "goodhost", dbc.Host)
assert.Equal(t, "gooddb", dbc.Name)
assert.Equal(t, "gooduser", dbc.User)
Expand All @@ -19,7 +18,8 @@ func TestParseConfigMultiDB(t *testing.T) {
}

func TestParseConfigSimpleDB(t *testing.T) {
dbc := dbConfigFromSource(t, fixtureBase+"/magento2/configs/simple.php", &magento2)
m2 := Magento2{}
dbc := dbConfigFromSource(t, fixtureBase+"/magento2/configs/simple.php", &m2)
assert.Equal(t, "goodhost", dbc.Host)
assert.Equal(t, "gooddb", dbc.Name)
assert.Equal(t, "gooduser", dbc.User)
Expand All @@ -30,37 +30,44 @@ func TestParseConfigSimpleDB(t *testing.T) {
}

func TestParseConfigEmpty(t *testing.T) {
dbc := dbConfigFromSource(t, fixtureBase+"/magento2/configs/empty.php", &magento2)
m2 := Magento2{}
dbc := dbConfigFromSource(t, fixtureBase+"/magento2/configs/empty.php", &m2)
assert.Nil(t, dbc)
}

func TestActualConfig(t *testing.T) {
dbc := dbConfigFromSource(t, fixtureBase+"/magento2/app/etc/env.php", &magento2)
m2 := Magento2{}
dbc := dbConfigFromSource(t, fixtureBase+"/magento2/app/etc/env.php", &m2)
assert.Equal(t, "", dbc.Prefix)
assert.Equal(t, "app:sldfjlskdfklds@tcp(localhost:3306)/magento2?allowOldPasswords=true", dbc.DSN())
}

func TestCrash1(t *testing.T) {
dbc := dbConfigFromSource(t, fixtureBase+"/magento2/configs/crash1.php", &magento2)
m2 := Magento2{}
dbc := dbConfigFromSource(t, fixtureBase+"/magento2/configs/crash1.php", &m2)
assert.Equal(t, "xx:xx@tcp(localhost:3306)/xx?allowOldPasswords=true", dbc.DSN())
}

func TestCrash2(t *testing.T) {
dbc := dbConfigFromSource(t, fixtureBase+"/magento2/configs/crash2.php", &magento2)
m2 := Magento2{}
dbc := dbConfigFromSource(t, fixtureBase+"/magento2/configs/crash2.php", &m2)
assert.Equal(t, "xx:xx@tcp(10.10.20.39:3306)/xx?allowOldPasswords=true", dbc.DSN())
}

func TestPHPParserDoesNotChokeOnListItems(t *testing.T) {
dbc := dbConfigFromSource(t, fixtureBase+"/magento2/configs/crash3.php", &magento2)
m2 := Magento2{}
dbc := dbConfigFromSource(t, fixtureBase+"/magento2/configs/crash3.php", &m2)
assert.Equal(t, "myuser:mypass@tcp(myhost:3306)/mydb?allowOldPasswords=true", dbc.DSN())
}

func TestPortInHost(t *testing.T) {
dbc := dbConfigFromSource(t, fixtureBase+"/magento2/configs/hostport.php", &magento2)
m2 := Magento2{}
dbc := dbConfigFromSource(t, fixtureBase+"/magento2/configs/hostport.php", &m2)
assert.Equal(t, "gooduser:verylongpassword@tcp(goodhost:3309)/gooddb?allowOldPasswords=true", dbc.DSN())
}

func TestScanNonExistantFile(t *testing.T) {
dbc := dbConfigFromSource(t, "/do/not/exist", &magento2)
m2 := Magento2{}
dbc := dbConfigFromSource(t, "/do/not/exist", &m2)
assert.Nil(t, dbc)
}
88 changes: 88 additions & 0 deletions opencart4.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
package gocommerce

import (
"errors"
"os"
"path/filepath"
"regexp"
"strconv"
)

type OpenCart4 struct {
basePlatform
}

var (
ocURLRgx = regexp.MustCompile(`define\('HTTP_SERVER',\s?'([^']+)'\);`)
ocVerRgx = regexp.MustCompile(`define\('VERSION',\s?'([^']+)'\);`)
ocLookupRgx = map[string]string{
"host": `define\('DB_HOSTNAME\',\s?'([^']+)'\);`,
"user": `define\('DB_USERNAME\',\s?'([^']+)'\);`,
"pass": `define\('DB_PASSWORD\',\s?'([^']+)'\);`,
"db": `define\('DB_DATABASE\',\s?'([^']+)'\);`,
"port": `define\('DB_PORT\',\s?'([^']+)'\);`,
"prefix": `define\('DB_PREFIX\',\s?'([^']+)'\);`,
}
)

func (oc4 *OpenCart4) ParseConfig(cfgPath string) (*StoreConfig, error) {
data, err := os.ReadFile(cfgPath)
if err != nil {
return nil, err
}

matches := map[string]string{}
for k, v := range ocLookupRgx {
m := regexp.MustCompile(v).FindStringSubmatch(string(data))
if len(m) != 2 {
continue
}
matches[k] = m[1]
}

port, err := strconv.Atoi(matches["port"])
if err != nil {
return nil, err
}

return &StoreConfig{
DB: &DBConfig{
Host: matches["host"],
User: matches["user"],
Pass: matches["pass"],
Name: matches["db"],
Prefix: matches["prefix"],
Port: port,
},
}, nil
}

func (oc4 *OpenCart4) BaseURLs(docroot string) ([]string, error) {
cfgPath := filepath.Join(docroot, "config.php")
cfg, err := os.ReadFile(cfgPath)
if err != nil {
return nil, err
}

match := ocURLRgx.FindSubmatch(cfg)
if len(match) < 2 {
return nil, errors.New("base url not found in config")
}

return []string{string(match[1])}, nil
}

func (oc4 *OpenCart4) Version(docroot string) (string, error) {
cfgPath := filepath.Join(docroot, "admin", "index.php")
cfg, err := os.ReadFile(cfgPath)
if err != nil {
return "", err
}

match := ocVerRgx.FindSubmatch(cfg)
if len(match) < 2 {
return "", errors.New("version not found in config")
}

return string(match[1]), nil
}
28 changes: 28 additions & 0 deletions opencart4_config_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
package gocommerce

import (
"testing"

"github.com/stretchr/testify/assert"
)

func TestOpenCartConfig(t *testing.T) {
oc4 := OpenCart4{}
dbc := dbConfigFromSource(t, fixtureBase+"opencart4/config.php", &oc4)
assert.Equal(t, dbc.DSN(), "root:root@tcp(localhost:3306)/opencart?allowOldPasswords=true")
}

func TestOpenCartURL(t *testing.T) {
oc4 := OpenCart4{}
urls, err := oc4.BaseURLs(fixtureBase + "opencart4")
assert.NoError(t, err)
assert.NotEmpty(t, urls)
assert.Equal(t, "http://sansec.io/", urls[0])
}

func TestOpenCartVersion(t *testing.T) {
oc4 := OpenCart4{}
ver, err := oc4.Version(fixtureBase + "opencart4")
assert.NoError(t, err)
assert.Equal(t, "4.0.2.3", ver)
}
6 changes: 4 additions & 2 deletions phpcfg/phpcfg_test.go
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
package phpcfg

import "testing"
import "github.com/google/go-cmp/cmp"
import (
"testing"
"github.com/google/go-cmp/cmp"
)

func TestParseShortArray(t *testing.T) {
src := `
Expand Down
Loading
Loading