Skip to content
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
19 changes: 17 additions & 2 deletions fields.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,16 @@ package publiccode
import (
"fmt"
"net/url"
"regexp"
"strings"

"github.com/alranel/go-vcsurl/v2"
urlutil "github.com/publiccodeyml/libpubliccode/v5/internal"
)

// RFC 3986 scheme = ALPHA *( ALPHA / DIGIT / "+" / "-" / "." ).
var urlSchemeRegexp = regexp.MustCompile(`^([A-Za-z][A-Za-z0-9+.-]*):`)

type validateFn func(publiccode PublicCode, parser *Parser, network bool, baseURL *url.URL) error

// validateFieldsV0 validates publiccode.yml with additional rules not validatable
Expand Down Expand Up @@ -453,8 +457,19 @@ func isRelativePathOrURL(content string, keyName string) (bool, error) {
return false, newValidationError(keyName, "is an absolute path. Only relative paths or HTTP(s) URLs allowed")
}

if strings.HasPrefix(content, "file:") {
return false, newValidationError(keyName, "is a file:// URL. Only relative paths or HTTP(s) URLs allowed")
// Not url.Parse: it fails on values like "file:///%zz", which would then
// pass as relative paths. URL schemes are case-insensitive (RFC 3986).
if m := urlSchemeRegexp.FindStringSubmatch(content); m != nil {
switch scheme := strings.ToLower(m[1]); scheme {
case "http", "https":
return true, nil
case "file":
return false, newValidationError(keyName, "is a file:// URL. Only relative paths or HTTP(s) URLs allowed")
default:
return false, newValidationErrorf(
keyName, "has an unsupported URL scheme '%s'. Only relative paths or HTTP(s) URLs allowed", scheme,
)
}
}

return true, nil
Expand Down
46 changes: 46 additions & 0 deletions fields_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
package publiccode

import (
"errors"
"testing"
)

func TestIsRelativePathOrURL(t *testing.T) {
tests := []struct {
content string
err string
}{
{"logo.png", ""},
{"img/logo.png", ""},
{"img/logo:1.png", ""},
{"logo%.png", ""},
{"https://example.org/logo.png", ""},
{"http://example.org/logo.png", ""},
{"HTTPS://example.org/logo.png", ""},
{"/logo.png", "is an absolute path. Only relative paths or HTTP(s) URLs allowed"},
{"file:///logo.png", "is a file:// URL. Only relative paths or HTTP(s) URLs allowed"},
{"FILE:///logo.png", "is a file:// URL. Only relative paths or HTTP(s) URLs allowed"},
{"File:///%zz.png", "is a file:// URL. Only relative paths or HTTP(s) URLs allowed"},
{"ftp://example.org/logo.png", "has an unsupported URL scheme 'ftp'. Only relative paths or HTTP(s) URLs allowed"},
{"data:image/png;base64,iVBORw0KGgo=", "has an unsupported URL scheme 'data'. Only relative paths or HTTP(s) URLs allowed"},
}

for _, tt := range tests {
t.Run(tt.content, func(t *testing.T) {
ok, err := isRelativePathOrURL(tt.content, "logo")

if tt.err == "" {
if !ok || err != nil {
t.Errorf("expected %q to be accepted, got %v", tt.content, err)
}

return
}

var ve ValidationError
if ok || !errors.As(err, &ve) || ve.Key != "logo" || ve.Description != tt.err {
t.Errorf("expected error %q for %q, got %v", tt.err, tt.content, err)
}
})
}
}
53 changes: 53 additions & 0 deletions testdata/v0/invalid/legal_authorsFile_file_scheme_uppercase.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
publiccodeYmlVersion: "0"

name: Medusa
url: "https://github.com/italia/developers.italia.it.git"
releaseDate: "2017-04-15"

platforms:
- web

categories:
- cloud-management

developmentStatus: development

softwareType: "standalone/other"

description:
en:
localisedName: Medusa
shortDescription: >
A rather short description which
is probably useless
longDescription: >
Very long description of this software, also split
on multiple rows. You should note what the software
is and why one should need it. This is 158 characters.
Very long description of this software, also split
on multiple rows. You should note what the software
is and why one should need it. This is 316 characters.
Very long description of this software, also split
on multiple rows. You should note what the software
is and why one should need it. This is 474 characters.
Very long description of this software, also split
on multiple rows. You should note what the software
is and why one should need it. This is 632 characters.
features:
- Just one feature

legal:
license: AGPL-3.0-or-later
# Should NOT validate: it has a "FILE:" scheme
authorsFile: 'FILE:///no_such_authors_file.txt'

maintenance:
type: "community"

contacts:
- name: Francesco Rossi

localisation:
localisationReady: true
availableLanguages:
- en
54 changes: 54 additions & 0 deletions testdata/v0/invalid/logo_data_scheme.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
publiccodeYmlVersion: "0"

name: Medusa
url: "https://github.com/italia/developers.italia.it.git"
releaseDate: "2017-04-15"

platforms:
- web

categories:
- cloud-management

developmentStatus: development

softwareType: "standalone/other"

# Should NOT validate: it has a "data:" scheme. logo must be either an HTTP URL or a relative path
logo: "data:image/png;base64,iVBORw0KGgo="

description:
en:
localisedName: Medusa
shortDescription: >
A rather short description which
is probably useless
longDescription: >
Very long description of this software, also split
on multiple rows. You should note what the software
is and why one should need it. This is 158 characters.
Very long description of this software, also split
on multiple rows. You should note what the software
is and why one should need it. This is 316 characters.
Very long description of this software, also split
on multiple rows. You should note what the software
is and why one should need it. This is 474 characters.
Very long description of this software, also split
on multiple rows. You should note what the software
is and why one should need it. This is 632 characters.
features:
- Just one feature

legal:
license: AGPL-3.0-or-later

maintenance:
type: "community"

contacts:
- name: Francesco Rossi

localisation:
localisationReady: true
availableLanguages:
- en
54 changes: 54 additions & 0 deletions testdata/v0/invalid/logo_file_scheme_mixed_case.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
publiccodeYmlVersion: "0"

name: Medusa
url: "https://github.com/italia/developers.italia.it.git"
releaseDate: "2017-04-15"

platforms:
- web

categories:
- cloud-management

developmentStatus: development

softwareType: "standalone/other"

# Should NOT validate: it has a "file:" scheme. logo must be either an HTTP URL or a relative path
logo: "File:///logo.png"

description:
en:
localisedName: Medusa
shortDescription: >
A rather short description which
is probably useless
longDescription: >
Very long description of this software, also split
on multiple rows. You should note what the software
is and why one should need it. This is 158 characters.
Very long description of this software, also split
on multiple rows. You should note what the software
is and why one should need it. This is 316 characters.
Very long description of this software, also split
on multiple rows. You should note what the software
is and why one should need it. This is 474 characters.
Very long description of this software, also split
on multiple rows. You should note what the software
is and why one should need it. This is 632 characters.
features:
- Just one feature

legal:
license: AGPL-3.0-or-later

maintenance:
type: "community"

contacts:
- name: Francesco Rossi

localisation:
localisationReady: true
availableLanguages:
- en
54 changes: 54 additions & 0 deletions testdata/v0/invalid/logo_file_scheme_uppercase.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
publiccodeYmlVersion: "0"

name: Medusa
url: "https://github.com/italia/developers.italia.it.git"
releaseDate: "2017-04-15"

platforms:
- web

categories:
- cloud-management

developmentStatus: development

softwareType: "standalone/other"

# Should NOT validate: it has a "file:" scheme. logo must be either an HTTP URL or a relative path
logo: "FILE:///logo.png"

description:
en:
localisedName: Medusa
shortDescription: >
A rather short description which
is probably useless
longDescription: >
Very long description of this software, also split
on multiple rows. You should note what the software
is and why one should need it. This is 158 characters.
Very long description of this software, also split
on multiple rows. You should note what the software
is and why one should need it. This is 316 characters.
Very long description of this software, also split
on multiple rows. You should note what the software
is and why one should need it. This is 474 characters.
Very long description of this software, also split
on multiple rows. You should note what the software
is and why one should need it. This is 632 characters.
features:
- Just one feature

legal:
license: AGPL-3.0-or-later

maintenance:
type: "community"

contacts:
- name: Francesco Rossi

localisation:
localisationReady: true
availableLanguages:
- en
54 changes: 54 additions & 0 deletions testdata/v0/invalid/logo_ftp_scheme.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
publiccodeYmlVersion: "0"

name: Medusa
url: "https://github.com/italia/developers.italia.it.git"
releaseDate: "2017-04-15"

platforms:
- web

categories:
- cloud-management

developmentStatus: development

softwareType: "standalone/other"

# Should NOT validate: it has an "ftp:" scheme. logo must be either an HTTP URL or a relative path
logo: "ftp://example.org/logo.png"

description:
en:
localisedName: Medusa
shortDescription: >
A rather short description which
is probably useless
longDescription: >
Very long description of this software, also split
on multiple rows. You should note what the software
is and why one should need it. This is 158 characters.
Very long description of this software, also split
on multiple rows. You should note what the software
is and why one should need it. This is 316 characters.
Very long description of this software, also split
on multiple rows. You should note what the software
is and why one should need it. This is 474 characters.
Very long description of this software, also split
on multiple rows. You should note what the software
is and why one should need it. This is 632 characters.
features:
- Just one feature

legal:
license: AGPL-3.0-or-later

maintenance:
type: "community"

contacts:
- name: Francesco Rossi

localisation:
localisationReady: true
availableLanguages:
- en
Loading
Loading