1
0
mirror of https://github.com/mgechev/revive.git synced 2025-10-30 23:37:49 +02:00
Files
revive/rule/unsecure_url_scheme.go
2025-08-27 17:18:37 +02:00

89 lines
2.2 KiB
Go

package rule
import (
"fmt"
"go/ast"
"go/token"
"strconv"
"strings"
"github.com/mgechev/revive/lint"
)
// UnsecureURLSchemeRule checks if a file contains string literals with unsecure URL schemes (for example: http://... in place of https://...).
type UnsecureURLSchemeRule struct{}
// Apply applied the rule to the given file.
func (*UnsecureURLSchemeRule) Apply(file *lint.File, _ lint.Arguments) []lint.Failure {
if file.IsTest() {
return nil // skip test files
}
var failures []lint.Failure
onFailure := func(failure lint.Failure) {
failures = append(failures, failure)
}
w := lintUnsecureURLSchemeRule{
onFailure: onFailure,
}
ast.Walk(w, file.AST)
return failures
}
// Name returns the rule name.
func (*UnsecureURLSchemeRule) Name() string {
return "unsecure-url-scheme"
}
type lintUnsecureURLSchemeRule struct {
onFailure func(lint.Failure)
}
const schemeSeparator = "://"
const schemeHTTP = "http"
const schemeWS = "ws"
const urlPrefixHTTP = schemeHTTP + schemeSeparator
const urlPrefixWS = schemeWS + schemeSeparator
const lenURLPrefixHTTP = len(urlPrefixHTTP)
const lenURLPrefixWS = len(urlPrefixWS)
func (w lintUnsecureURLSchemeRule) Visit(node ast.Node) ast.Visitor {
n, ok := node.(*ast.BasicLit)
if !ok || n.Kind != token.STRING {
return w // not a string literal
}
value, _ := strconv.Unquote(n.Value) // n.Value has one of the following forms: "..." or `...`
var scheme string
var lenURLPrefix int
switch {
case strings.HasPrefix(value, urlPrefixHTTP):
scheme = schemeHTTP
lenURLPrefix = lenURLPrefixHTTP
case strings.HasPrefix(value, urlPrefixWS):
scheme = schemeWS
lenURLPrefix = lenURLPrefixWS
default:
return nil // not an URL or not an unsecure one
}
if len(value) <= lenURLPrefix {
return nil // there is no host part in the string
}
if strings.Contains(value, "localhost") || strings.Contains(value, "127.0.0.1") || strings.Contains(value, "0.0.0.0") || strings.Contains(value, "//::") {
return nil // do not fail on local URL
}
w.onFailure(lint.Failure{
Confidence: 1,
Failure: fmt.Sprintf("prefer secure protocol %s over %s in %s", scheme+"s", scheme, n.Value),
Node: n,
})
return nil
}