Received: from mail.netlandish.com (mail.netlandish.com [174.136.98.166])
	by code.netlandish.com (Postfix) with ESMTP id AEE41A4
	for <~netlandish/links-dev@lists.code.netlandish.com>; Thu, 10 Jul 2025 23:39:18 +0000 (UTC)
Received-SPF: Pass (mailfrom) identity=mailfrom; client-ip=209.85.219.181; helo=mail-yb1-f181.google.com; envelope-from=peter@netlandish.com; receiver=<UNKNOWN> 
Authentication-Results: mail.netlandish.com;
	dkim=pass (1024-bit key; unprotected) header.d=netlandish.com header.i=@netlandish.com header.b=A2WkTBA6
Received: from mail-yb1-f181.google.com (mail-yb1-f181.google.com [209.85.219.181])
	by mail.netlandish.com (Postfix) with ESMTP id A64331D640A
	for <~netlandish/links-dev@lists.code.netlandish.com>; Thu, 10 Jul 2025 23:39:57 +0000 (UTC)
Received: by mail-yb1-f181.google.com with SMTP id 3f1490d57ef6-e85e06a7f63so1317609276.1
        for <~netlandish/links-dev@lists.code.netlandish.com>; Thu, 10 Jul 2025 16:39:57 -0700 (PDT)
DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed;
        d=netlandish.com; s=google; t=1752190796; x=1752795596; darn=lists.code.netlandish.com;
        h=content-transfer-encoding:mime-version:message-id:date:subject:cc
         :to:from:from:to:cc:subject:date:message-id:reply-to;
        bh=wMGJXTGoXvPrvsCOLhkMrYaxtAYzFMD7cDwcVF2665Y=;
        b=A2WkTBA6j9FhwfErQhU2ijewo1c1cV3SnCAcAqyPF9ZFnVsbTLG9FUWooneD+ReEiQ
         7oUNN80VYc77B7x8DEHlY743srk13AGW1fh9OM80Bj3OMkxt/3aGra6rh3odpumRBsFc
         r7cKyXRxE98NMNaZXayep+gxEBlJS3BplrkjA=
X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed;
        d=1e100.net; s=20230601; t=1752190796; x=1752795596;
        h=content-transfer-encoding:mime-version:message-id:date:subject:cc
         :to:from:x-gm-message-state:from:to:cc:subject:date:message-id
         :reply-to;
        bh=wMGJXTGoXvPrvsCOLhkMrYaxtAYzFMD7cDwcVF2665Y=;
        b=RFBb3eUus5Z6F5a96JidK+Gy0vRblsLoJ2koTGwflNVpjqu3RavJb/ue85MLPY+py8
         6YL1bPCHoZdsR4DZn3yXNTktRCXW3SK6XYEwQwhkFFAUAENgy2Z22cEzwkL75jaFK4cl
         ry0aD/LC+Rg/1BRwrZvA5RiZu/OxBLVZjSGWzJP9YRqqBLNw+Agj+Zr0lBXytJR4cNQ2
         NRAuX9T6LFFKB92KLNssf7liJZ3NjqNvcIA7OSL7K7gsiX+36URTuWEPDS9YvZ0VLWvJ
         bu7wtnuicGv8nrEBB33ixOeeSSNnYjJpW0Zbz/X/gkzV9jndxTXikZFMz8Upt7u3f/bx
         opZg==
X-Gm-Message-State: AOJu0YwaY9nRYCywPOJKgpI34Xg37sXbXNSsuM+3VrBFptA/AUQ0IseP
	Odolj1+CMwmnv2bvi6CtYG/tZHoHlLZKH1Ph+QyHkl53+jYTSZnFyYOabuYl+gtGAh4MLR3Pypn
	yiEjJHjQ=
X-Gm-Gg: ASbGncu1JpHpURqyAVnDDOGb9TuJAb8wMB0zn0/0d2M3keueXDcarccsZqIMfDN4u2M
	9/ALLuecA9V2/ze4bNiKnjosCrRC25Pm+aCUOylJlYxwFG0LOFI8gUzyCSw855SHEO3PDYTdNV9
	UZaPSKhv8oMkNk6Xu5bQkoVFA+5HGn/eP9mYYdFT9Wm0EsMmCPeERRqyHdIsLhuUB7uyFl+ipQm
	RMkrcKhTYSencjNGxU3370e0lhETAAwgnW5VdNnsEzfASFavv+Y25bGapRgxie4XthUvjN84k3e
	GQIG1K1O/kIjAhrK1Bn2qqGPH2xHdUHPtBlRLQRDblAjNJSDoUYTryJKq7GRsSsYNkeMl1Z3WRS
	tKlde+LmCETjqXhrBw317ed0=
X-Google-Smtp-Source: AGHT+IFQDsDzjqBMfIP3wzdAy75fK1sJqL7Ka3n/hb6/t+WyGXdjAcOx1QlLZqHf5XM10/5sNci77A==
X-Received: by 2002:a05:6902:2d81:b0:e8b:6c20:149c with SMTP id 3f1490d57ef6-e8b85b96548mr912385276.45.1752190796538;
        Thu, 10 Jul 2025 16:39:56 -0700 (PDT)
Received: from localhost ([2803:2d60:1118:5ee:9101:a8cc:1bd9:7598])
        by smtp.gmail.com with UTF8SMTPSA id 3f1490d57ef6-e8b7afcc5ddsm712892276.42.2025.07.10.16.39.55
        (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256);
        Thu, 10 Jul 2025 16:39:55 -0700 (PDT)
From: Peter Sanchez <peter@netlandish.com>
To: ~netlandish/links-dev@lists.code.netlandish.com
Cc: Peter Sanchez <peter@netlandish.com>
Subject: [PATCH links] Limit the tag search input to 50 chars. Also escape extra characters to avoid query errors.
Date: Thu, 10 Jul 2025 17:39:51 -0600
Message-ID: <20250710233953.27697-1-peter@netlandish.com>
X-Mailer: git-send-email 2.49.0
MIME-Version: 1.0
Content-Transfer-Encoding: 8bit

Changelog-fixed: Issue where tag characters can cause PostgreSQL to
  return errors. Also limit tag queries to tag name limit (50).
---
 core/routes.go |  2 +-
 helpers.go     | 15 ++++++++++++---
 2 files changed, 13 insertions(+), 4 deletions(-)

diff --git a/core/routes.go b/core/routes.go
index aa0c9f5..74ed039 100644
--- a/core/routes.go
+++ b/core/routes.go
@@ -3370,7 +3370,7 @@ func (s *Service) TagAutocomplete(c echo.Context) error {
 	gctx := c.(*server.Context)
 	user := gctx.User.(*models.User)
 	orgID := c.QueryParam("org")
-	q := links.ParseSearch(c.QueryParam("q"))
+	q := links.ParseSearchTag(c.QueryParam("q"))
 	var (
 		tags []*models.Tag
 		err  error
diff --git a/helpers.go b/helpers.go
index 53dd36f..c10907a 100644
--- a/helpers.go
+++ b/helpers.go
@@ -404,7 +404,7 @@ func ParseBaseURL(ctx context.Context, baseURL *models.BaseURL) error {
 		return err
 	}
 
-	baseURL.ParseAttempts += 1
+	baseURL.ParseAttempts++
 	baseURL.LastParseAttempt = sql.NullTime{Valid: true, Time: time.Now().UTC()}
 
 	userAgent := BuildUserAgent(ctx)
@@ -583,8 +583,8 @@ func RenderRestrictedTemplate(c echo.Context) error {
 	gmap := gobwebs.Map{
 		"pd": pd,
 	}
-	if pass_msg, ok := c.Get("pass_msg").(string); ok {
-		gmap["pass_msg"] = pass_msg
+	if passMsg, ok := c.Get("pass_msg").(string); ok {
+		gmap["pass_msg"] = passMsg
 	}
 	curSlug := PullOrgSlug(c)
 	if curSlug != "" {
@@ -877,6 +877,7 @@ func ParseSearch(s string) string {
 			word = strings.TrimSpace(word)
 			word = strings.Replace(word, ":", "\\:", -1)
 			word = strings.Replace(word, "|", "\\|", -1)
+			word = strings.Replace(word, "!", "\\!", -1)
 			if !strings.HasPrefix(word, "-") {
 				word = word + ":*"
 			}
@@ -887,6 +888,14 @@ func ParseSearch(s string) string {
 	return s
 }
 
+// ParseSearchTag is just a helper to limit the size of the input query
+func ParseSearchTag(s string) string {
+	if len(s) > 50 {
+		s = s[:50]
+	}
+	return ParseSearch(s)
+}
+
 func AddQueryElement(q template.URL, param, val string, replace bool) template.URL {
 	query, err := url.ParseQuery(string(q))
 	if err != nil {
-- 
2.49.0

