From 0bda50c91716b2418220c4fb126f0ef7a9acbcb9 Mon Sep 17 00:00:00 2001 From: kzoeps Date: Tue, 10 Nov 2026 16:20:18 +0600 Subject: [PATCH] lua: share one NSID validator across endpoints Eight endpoints carried private copies of the same NSID check. They accept identical inputs, so they are replaced by lua/shared/nsidValidation.lua and added to the eight bundles that use it. Endpoint behavior is unchanged. --- .../lua/endpoints/getActorReactions.lua | 35 ++++++++++--------- .../lua/endpoints/getEntityFollows.lua | 34 +++++++++--------- .../lua/endpoints/getReactionCounts.lua | 35 ++++++++++--------- .../lua/endpoints/listAcknowledgements.lua | 33 ++++++++--------- .../lua/endpoints/listBadgeAwards.lua | 35 ++++++++++--------- .../lua/endpoints/listEvaluations.lua | 8 ++--- .../lua/endpoints/listMeasurements.lua | 7 ++-- .../lua/endpoints/listReceipts.lua | 30 +++++++--------- .../lua/shared/acknowledgementList.lua | 16 --------- .../lua/shared/evaluationList.lua | 21 ----------- .../lua/shared/feedActorReactions.lua | 18 +--------- .../lua/shared/fundingReceiptList.lua | 23 +----------- .../lua/shared/nsidValidation.lua | 16 +++++++++ .../lua/src/getEntityFollows.lua | 17 --------- .../lua/src/getReactionCounts.lua | 18 +--------- happyview-modules/lua/src/listBadgeAwards.lua | 18 +--------- .../lua/src/listMeasurements.lua | 20 ----------- .../modules/acknowledgements/manifest.json | 1 + .../modules/badge-queries/manifest.json | 3 +- .../modules/context-evaluation/manifest.json | 1 + .../context-measurements/manifest.json | 3 +- .../modules/entity-follow/manifest.json | 3 +- .../modules/feed-reactions/manifest.json | 4 ++- .../modules/funding/manifest.json | 1 + 24 files changed, 137 insertions(+), 263 deletions(-) create mode 100644 happyview-modules/lua/shared/nsidValidation.lua diff --git a/happyview-modules/lua/endpoints/getActorReactions.lua b/happyview-modules/lua/endpoints/getActorReactions.lua index 717bad3e..dab2fca3 100644 --- a/happyview-modules/lua/endpoints/getActorReactions.lua +++ b/happyview-modules/lua/endpoints/getActorReactions.lua @@ -51,6 +51,23 @@ local function record_view(row) } end +-- An atproto NSID: at least three dot-separated segments, at most 317 characters. +local function valid_nsid(value) + if type(value) ~= "string" or #value > 317 then return false end + local segments = {} + for segment in value:gmatch("[^%.]+") do segments[#segments + 1] = segment end + if #segments < 3 or table.concat(segments, ".") ~= value then return false end + for index = 1, #segments - 1 do + local segment = segments[index] + if #segment > 63 or segment:find("[^A-Za-z0-9%-]") then return false end + local first, last = segment:sub(1, 1), segment:sub(-1) + if not first:match(index == 1 and "^[A-Za-z]$" or "^[A-Za-z0-9]$") + or not last:match("^[A-Za-z0-9]$") then return false end + end + local name = segments[#segments] + return #name <= 63 and name:match("^[A-Za-z][A-Za-z0-9]*$") ~= nil +end + local ACTOR_REACTION_NULL = json.decode("null") local ACTOR_REACTION_LIMIT = 100 local ACTOR_REACTION_COLLECTIONS = { @@ -67,25 +84,9 @@ local function actor_reaction_sort_key() ", 'timestamptz') THEN (" .. created .. ")::timestamptz ELSE COALESCE(indexed_at::timestamptz, created_at::timestamptz) END" end -local function valid_actor_reaction_nsid(value) - if type(value) ~= "string" or #value > 317 then return false end - local segments = {} - for segment in value:gmatch("[^%.]+") do segments[#segments + 1] = segment end - if #segments < 3 or table.concat(segments, ".") ~= value then return false end - for index = 1, #segments - 1 do - local segment = segments[index] - if #segment > 63 or segment:find("[^A-Za-z0-9%-]") then return false end - local first, last = segment:sub(1, 1), segment:sub(-1) - if not first:match(index == 1 and "^[A-Za-z]$" or "^[A-Za-z0-9]$") - or not last:match("^[A-Za-z0-9]$") then return false end - end - local name = segments[#segments] - return #name <= 63 and name:match("^[A-Za-z][A-Za-z0-9]*$") ~= nil -end - local function valid_actor_reaction_subject_uri(value) local valid, collection = valid_record_uri(value) - return valid and valid_actor_reaction_nsid(collection) + return valid and valid_nsid(collection) end local function feed_actor_reaction_subjects(value) diff --git a/happyview-modules/lua/endpoints/getEntityFollows.lua b/happyview-modules/lua/endpoints/getEntityFollows.lua index e22319e5..882bb606 100644 --- a/happyview-modules/lua/endpoints/getEntityFollows.lua +++ b/happyview-modules/lua/endpoints/getEntityFollows.lua @@ -142,27 +142,27 @@ local function follow_batch_targets(actor, key, value, validate, description, en return targets, unique end +-- An atproto NSID: at least three dot-separated segments, at most 317 characters. +local function valid_nsid(value) + if type(value) ~= "string" or #value > 317 then return false end + local segments = {} + for segment in value:gmatch("[^%.]+") do segments[#segments + 1] = segment end + if #segments < 3 or table.concat(segments, ".") ~= value then return false end + for index = 1, #segments - 1 do + local segment = segments[index] + if #segment > 63 or segment:find("[^A-Za-z0-9%-]") then return false end + local first, last = segment:sub(1, 1), segment:sub(-1) + if not first:match(index == 1 and "^[A-Za-z]$" or "^[A-Za-z0-9]$") + or not last:match("^[A-Za-z0-9]$") then return false end + end + local name = segments[#segments] + return #name <= 63 and name:match("^[A-Za-z][A-Za-z0-9]*$") ~= nil +end + local function get_entity_follows() keys_only(params, { actor = true, entities = true }) local actor = scalar(params, "actor") if not actor or not valid_did(actor) then invalid("actor must be a valid DID") end - local function valid_nsid(value) - if type(value) ~= "string" or #value > 317 then return false end - local segments = {} - for segment in value:gmatch("[^%.]+") do segments[#segments + 1] = segment end - if #segments < 3 or table.concat(segments, ".") ~= value then return false end - - for _, segment in ipairs(segments) do - if #segment > 63 or segment:find("[^A-Za-z0-9%-]") - or segment:sub(1, 1) == "-" or segment:sub(-1) == "-" then - return false - end - end - - if not segments[1]:sub(1, 1):match("^[A-Za-z]$") then return false end - return segments[#segments]:match("^[A-Za-z][A-Za-z0-9]*$") ~= nil - end - local function valid_entity_uri(value) if #value > 8192 then return false end local valid, collection = valid_record_uri(value) diff --git a/happyview-modules/lua/endpoints/getReactionCounts.lua b/happyview-modules/lua/endpoints/getReactionCounts.lua index 15d19196..311b2728 100644 --- a/happyview-modules/lua/endpoints/getReactionCounts.lua +++ b/happyview-modules/lua/endpoints/getReactionCounts.lua @@ -39,6 +39,23 @@ local function valid_record_uri(value) return true, collection, authority end +-- An atproto NSID: at least three dot-separated segments, at most 317 characters. +local function valid_nsid(value) + if type(value) ~= "string" or #value > 317 then return false end + local segments = {} + for segment in value:gmatch("[^%.]+") do segments[#segments + 1] = segment end + if #segments < 3 or table.concat(segments, ".") ~= value then return false end + for index = 1, #segments - 1 do + local segment = segments[index] + if #segment > 63 or segment:find("[^A-Za-z0-9%-]") then return false end + local first, last = segment:sub(1, 1), segment:sub(-1) + if not first:match(index == 1 and "^[A-Za-z]$" or "^[A-Za-z0-9]$") + or not last:match("^[A-Za-z0-9]$") then return false end + end + local name = segments[#segments] + return #name <= 63 and name:match("^[A-Za-z][A-Za-z0-9]*$") ~= nil +end + local LIKE = "app.certified.feed.like" local REPOST = "app.certified.feed.repost" @@ -55,22 +72,6 @@ local function reaction_count_valid_did_percent_escapes(authority) return true end -local function reaction_count_valid_nsid(value) - if type(value) ~= "string" or #value > 317 then return false end - local segments = {} - for segment in value:gmatch("[^%.]+") do segments[#segments + 1] = segment end - if #segments < 3 or table.concat(segments, ".") ~= value then return false end - for index = 1, #segments - 1 do - local segment = segments[index] - if #segment > 63 or segment:find("[^A-Za-z0-9%-]") then return false end - local first, last = segment:sub(1, 1), segment:sub(-1) - if not first:match(index == 1 and "^[A-Za-z]$" or "^[A-Za-z0-9]$") - or not last:match("^[A-Za-z0-9]$") then return false end - end - local name = segments[#segments] - return #name <= 63 and name:match("^[A-Za-z][A-Za-z0-9]*$") ~= nil -end - local function reaction_count_subjects() local value = params.subjects if value == nil then invalid("subjects is required") end @@ -104,7 +105,7 @@ local function reaction_count_subjects() for _, subject in ipairs(supplied) do local valid, collection, authority = valid_record_uri(subject) if not valid or not reaction_count_valid_did_percent_escapes(authority) - or not reaction_count_valid_nsid(collection) then + or not valid_nsid(collection) then invalid("each subjects value must be a full AT-URI with a valid DID authority and collection NSID") end if not seen[subject] then diff --git a/happyview-modules/lua/endpoints/listAcknowledgements.lua b/happyview-modules/lua/endpoints/listAcknowledgements.lua index 3da756ed..ff6fba61 100644 --- a/happyview-modules/lua/endpoints/listAcknowledgements.lua +++ b/happyview-modules/lua/endpoints/listAcknowledgements.lua @@ -130,22 +130,7 @@ local function hydrate_acknowledgement_authors(views) end end -local generic_valid_datetime = valid_datetime - -local function acknowledgement_valid_datetime(value) - if type(value) ~= "string" then return false end - if value:match("^(%d%d%d%d)") == "0000" then return false end - return generic_valid_datetime(value) -end - -local function valid_cursor_timestamp(value) - if type(value) ~= "string" or #value ~= 27 - or not value:match("^%d%d%d%d%-%d%d%-%d%dT%d%d:%d%d:%d%d%.%d%d%d%d%d%dZ$") then - return false - end - return acknowledgement_valid_datetime(value) -end - +-- An atproto NSID: at least three dot-separated segments, at most 317 characters. local function valid_nsid(value) if type(value) ~= "string" or #value > 317 then return false end local segments = {} @@ -162,6 +147,22 @@ local function valid_nsid(value) return #name <= 63 and name:match("^[A-Za-z][A-Za-z0-9]*$") ~= nil end +local generic_valid_datetime = valid_datetime + +local function acknowledgement_valid_datetime(value) + if type(value) ~= "string" then return false end + if value:match("^(%d%d%d%d)") == "0000" then return false end + return generic_valid_datetime(value) +end + +local function valid_cursor_timestamp(value) + if type(value) ~= "string" or #value ~= 27 + or not value:match("^%d%d%d%d%-%d%d%-%d%dT%d%d:%d%d:%d%d%.%d%d%d%d%d%dZ$") then + return false + end + return acknowledgement_valid_datetime(value) +end + local function acknowledgement_array(key, format) local value = params[key] if value == nil then return nil end diff --git a/happyview-modules/lua/endpoints/listBadgeAwards.lua b/happyview-modules/lua/endpoints/listBadgeAwards.lua index 3c615989..b5d0df37 100644 --- a/happyview-modules/lua/endpoints/listBadgeAwards.lua +++ b/happyview-modules/lua/endpoints/listBadgeAwards.lua @@ -123,22 +123,8 @@ local function hydrate_actor_views(actors, run_query) end end -local AWARD = "app.certified.badge.award" -local DEFINITION = "app.certified.badge.definition" -local RESPONSE = "app.certified.badge.response" -local RESPONSE_STATUSES = { accepted = true, rejected = true, unanswered = true } - -local function valid_badge_award_uri(value) - local valid, collection = valid_record_uri(value) - return valid and collection == AWARD -end - -local function valid_badge_definition_uri(value) - local valid, collection = valid_record_uri(value) - return valid and collection == DEFINITION -end - -local function valid_badge_subject_nsid(value) +-- An atproto NSID: at least three dot-separated segments, at most 317 characters. +local function valid_nsid(value) if type(value) ~= "string" or #value > 317 then return false end local segments = {} for segment in value:gmatch("[^%.]+") do segments[#segments + 1] = segment end @@ -154,6 +140,21 @@ local function valid_badge_subject_nsid(value) return #name <= 63 and name:match("^[A-Za-z][A-Za-z0-9]*$") ~= nil end +local AWARD = "app.certified.badge.award" +local DEFINITION = "app.certified.badge.definition" +local RESPONSE = "app.certified.badge.response" +local RESPONSE_STATUSES = { accepted = true, rejected = true, unanswered = true } + +local function valid_badge_award_uri(value) + local valid, collection = valid_record_uri(value) + return valid and collection == AWARD +end + +local function valid_badge_definition_uri(value) + local valid, collection = valid_record_uri(value) + return valid and collection == DEFINITION +end + local function query(sql, values) if db.backend() ~= "postgres" then error("BadgeAwardQueryFailed: badge award API requires PostgreSQL", 0) @@ -205,7 +206,7 @@ local function subject_values() local is_did = valid_did(item) local valid_uri, collection if not is_did then valid_uri, collection = valid_record_uri(item) end - if not is_did and (not valid_uri or not valid_badge_subject_nsid(collection)) then + if not is_did and (not valid_uri or not valid_nsid(collection)) then invalid("subjects[" .. index .. "] must be a valid DID or full record AT-URI with a valid collection NSID") end if not seen[item] then diff --git a/happyview-modules/lua/endpoints/listEvaluations.lua b/happyview-modules/lua/endpoints/listEvaluations.lua index 90126461..c0232b88 100644 --- a/happyview-modules/lua/endpoints/listEvaluations.lua +++ b/happyview-modules/lua/endpoints/listEvaluations.lua @@ -206,23 +206,19 @@ local function hydrate_evaluation_views(views) end end +-- An atproto NSID: at least three dot-separated segments, at most 317 characters. local function valid_nsid(value) if type(value) ~= "string" or #value > 317 then return false end - local segments = {} for segment in value:gmatch("[^%.]+") do segments[#segments + 1] = segment end if #segments < 3 or table.concat(segments, ".") ~= value then return false end - for index = 1, #segments - 1 do local segment = segments[index] if #segment > 63 or segment:find("[^A-Za-z0-9%-]") then return false end local first, last = segment:sub(1, 1), segment:sub(-1) if not first:match(index == 1 and "^[A-Za-z]$" or "^[A-Za-z0-9]$") - or not last:match("^[A-Za-z0-9]$") then - return false - end + or not last:match("^[A-Za-z0-9]$") then return false end end - local name = segments[#segments] return #name <= 63 and name:match("^[A-Za-z][A-Za-z0-9]*$") ~= nil end diff --git a/happyview-modules/lua/endpoints/listMeasurements.lua b/happyview-modules/lua/endpoints/listMeasurements.lua index 85f0d628..b1be923d 100644 --- a/happyview-modules/lua/endpoints/listMeasurements.lua +++ b/happyview-modules/lua/endpoints/listMeasurements.lua @@ -165,22 +165,19 @@ local function hydrate_measurement_views(views) end end +-- An atproto NSID: at least three dot-separated segments, at most 317 characters. local function valid_nsid(value) if type(value) ~= "string" or #value > 317 then return false end local segments = {} for segment in value:gmatch("[^%.]+") do segments[#segments + 1] = segment end if #segments < 3 or table.concat(segments, ".") ~= value then return false end - for index = 1, #segments - 1 do local segment = segments[index] if #segment > 63 or segment:find("[^A-Za-z0-9%-]") then return false end local first, last = segment:sub(1, 1), segment:sub(-1) if not first:match(index == 1 and "^[A-Za-z]$" or "^[A-Za-z0-9]$") - or not last:match("^[A-Za-z0-9]$") then - return false - end + or not last:match("^[A-Za-z0-9]$") then return false end end - local name = segments[#segments] return #name <= 63 and name:match("^[A-Za-z][A-Za-z0-9]*$") ~= nil end diff --git a/happyview-modules/lua/endpoints/listReceipts.lua b/happyview-modules/lua/endpoints/listReceipts.lua index 6c33a906..fa320206 100644 --- a/happyview-modules/lua/endpoints/listReceipts.lua +++ b/happyview-modules/lua/endpoints/listReceipts.lua @@ -147,30 +147,26 @@ local function hydrate_funding_receipt_views(views) end end -local function valid_funding_nsid(value) - if type(value) ~= "string" or #value < 5 or #value > 317 or value:find("[^A-Za-z0-9.%-]") then - return false - end +-- An atproto NSID: at least three dot-separated segments, at most 317 characters. +local function valid_nsid(value) + if type(value) ~= "string" or #value > 317 then return false end local segments = {} - for segment in value:gmatch("[^.]+") do segments[#segments + 1] = segment end + for segment in value:gmatch("[^%.]+") do segments[#segments + 1] = segment end if #segments < 3 or table.concat(segments, ".") ~= value then return false end - - for index, segment in ipairs(segments) do - if #segment > 63 or segment:find("^[%-]") or segment:find("[%-]$") then return false end - if index == 1 then - if not segment:match("^[A-Za-z]") then return false end - elseif index == #segments then - if not segment:match("^[A-Za-z][A-Za-z0-9]*$") then return false end - elseif not segment:match("^[A-Za-z0-9]") then - return false - end + for index = 1, #segments - 1 do + local segment = segments[index] + if #segment > 63 or segment:find("[^A-Za-z0-9%-]") then return false end + local first, last = segment:sub(1, 1), segment:sub(-1) + if not first:match(index == 1 and "^[A-Za-z]$" or "^[A-Za-z0-9]$") + or not last:match("^[A-Za-z0-9]$") then return false end end - return true + local name = segments[#segments] + return #name <= 63 and name:match("^[A-Za-z][A-Za-z0-9]*$") ~= nil end local function valid_funding_record_uri(value) local valid, collection = valid_record_uri(value) - if not valid or not valid_funding_nsid(collection) then return false, collection end + if not valid or not valid_nsid(collection) then return false, collection end return true, collection end diff --git a/happyview-modules/lua/shared/acknowledgementList.lua b/happyview-modules/lua/shared/acknowledgementList.lua index d57fec01..ef3773e5 100644 --- a/happyview-modules/lua/shared/acknowledgementList.lua +++ b/happyview-modules/lua/shared/acknowledgementList.lua @@ -14,22 +14,6 @@ local function valid_cursor_timestamp(value) return acknowledgement_valid_datetime(value) end -local function valid_nsid(value) - if type(value) ~= "string" or #value > 317 then return false end - local segments = {} - for segment in value:gmatch("[^%.]+") do segments[#segments + 1] = segment end - if #segments < 3 or table.concat(segments, ".") ~= value then return false end - for index = 1, #segments - 1 do - local segment = segments[index] - if #segment > 63 or segment:find("[^A-Za-z0-9%-]") then return false end - local first, last = segment:sub(1, 1), segment:sub(-1) - if not first:match(index == 1 and "^[A-Za-z]$" or "^[A-Za-z0-9]$") - or not last:match("^[A-Za-z0-9]$") then return false end - end - local name = segments[#segments] - return #name <= 63 and name:match("^[A-Za-z][A-Za-z0-9]*$") ~= nil -end - local function acknowledgement_array(key, format) local value = params[key] if value == nil then return nil end diff --git a/happyview-modules/lua/shared/evaluationList.lua b/happyview-modules/lua/shared/evaluationList.lua index e737b2b0..febddba5 100644 --- a/happyview-modules/lua/shared/evaluationList.lua +++ b/happyview-modules/lua/shared/evaluationList.lua @@ -1,24 +1,3 @@ -local function valid_nsid(value) - if type(value) ~= "string" or #value > 317 then return false end - - local segments = {} - for segment in value:gmatch("[^%.]+") do segments[#segments + 1] = segment end - if #segments < 3 or table.concat(segments, ".") ~= value then return false end - - for index = 1, #segments - 1 do - local segment = segments[index] - if #segment > 63 or segment:find("[^A-Za-z0-9%-]") then return false end - local first, last = segment:sub(1, 1), segment:sub(-1) - if not first:match(index == 1 and "^[A-Za-z]$" or "^[A-Za-z0-9]$") - or not last:match("^[A-Za-z0-9]$") then - return false - end - end - - local name = segments[#segments] - return #name <= 63 and name:match("^[A-Za-z][A-Za-z0-9]*$") ~= nil -end - local function evaluation_array(key, format) local value = params[key] if value == nil then return nil end diff --git a/happyview-modules/lua/shared/feedActorReactions.lua b/happyview-modules/lua/shared/feedActorReactions.lua index 9e27defa..578ff264 100644 --- a/happyview-modules/lua/shared/feedActorReactions.lua +++ b/happyview-modules/lua/shared/feedActorReactions.lua @@ -14,25 +14,9 @@ local function actor_reaction_sort_key() ", 'timestamptz') THEN (" .. created .. ")::timestamptz ELSE COALESCE(indexed_at::timestamptz, created_at::timestamptz) END" end -local function valid_actor_reaction_nsid(value) - if type(value) ~= "string" or #value > 317 then return false end - local segments = {} - for segment in value:gmatch("[^%.]+") do segments[#segments + 1] = segment end - if #segments < 3 or table.concat(segments, ".") ~= value then return false end - for index = 1, #segments - 1 do - local segment = segments[index] - if #segment > 63 or segment:find("[^A-Za-z0-9%-]") then return false end - local first, last = segment:sub(1, 1), segment:sub(-1) - if not first:match(index == 1 and "^[A-Za-z]$" or "^[A-Za-z0-9]$") - or not last:match("^[A-Za-z0-9]$") then return false end - end - local name = segments[#segments] - return #name <= 63 and name:match("^[A-Za-z][A-Za-z0-9]*$") ~= nil -end - local function valid_actor_reaction_subject_uri(value) local valid, collection = valid_record_uri(value) - return valid and valid_actor_reaction_nsid(collection) + return valid and valid_nsid(collection) end local function feed_actor_reaction_subjects(value) diff --git a/happyview-modules/lua/shared/fundingReceiptList.lua b/happyview-modules/lua/shared/fundingReceiptList.lua index 8fddb8dc..263b9655 100644 --- a/happyview-modules/lua/shared/fundingReceiptList.lua +++ b/happyview-modules/lua/shared/fundingReceiptList.lua @@ -1,27 +1,6 @@ -local function valid_funding_nsid(value) - if type(value) ~= "string" or #value < 5 or #value > 317 or value:find("[^A-Za-z0-9.%-]") then - return false - end - local segments = {} - for segment in value:gmatch("[^.]+") do segments[#segments + 1] = segment end - if #segments < 3 or table.concat(segments, ".") ~= value then return false end - - for index, segment in ipairs(segments) do - if #segment > 63 or segment:find("^[%-]") or segment:find("[%-]$") then return false end - if index == 1 then - if not segment:match("^[A-Za-z]") then return false end - elseif index == #segments then - if not segment:match("^[A-Za-z][A-Za-z0-9]*$") then return false end - elseif not segment:match("^[A-Za-z0-9]") then - return false - end - end - return true -end - local function valid_funding_record_uri(value) local valid, collection = valid_record_uri(value) - if not valid or not valid_funding_nsid(collection) then return false, collection end + if not valid or not valid_nsid(collection) then return false, collection end return true, collection end diff --git a/happyview-modules/lua/shared/nsidValidation.lua b/happyview-modules/lua/shared/nsidValidation.lua new file mode 100644 index 00000000..e7bd55a4 --- /dev/null +++ b/happyview-modules/lua/shared/nsidValidation.lua @@ -0,0 +1,16 @@ +-- An atproto NSID: at least three dot-separated segments, at most 317 characters. +local function valid_nsid(value) + if type(value) ~= "string" or #value > 317 then return false end + local segments = {} + for segment in value:gmatch("[^%.]+") do segments[#segments + 1] = segment end + if #segments < 3 or table.concat(segments, ".") ~= value then return false end + for index = 1, #segments - 1 do + local segment = segments[index] + if #segment > 63 or segment:find("[^A-Za-z0-9%-]") then return false end + local first, last = segment:sub(1, 1), segment:sub(-1) + if not first:match(index == 1 and "^[A-Za-z]$" or "^[A-Za-z0-9]$") + or not last:match("^[A-Za-z0-9]$") then return false end + end + local name = segments[#segments] + return #name <= 63 and name:match("^[A-Za-z][A-Za-z0-9]*$") ~= nil +end diff --git a/happyview-modules/lua/src/getEntityFollows.lua b/happyview-modules/lua/src/getEntityFollows.lua index 148059d1..d2f3cde3 100644 --- a/happyview-modules/lua/src/getEntityFollows.lua +++ b/happyview-modules/lua/src/getEntityFollows.lua @@ -2,23 +2,6 @@ local function get_entity_follows() keys_only(params, { actor = true, entities = true }) local actor = scalar(params, "actor") if not actor or not valid_did(actor) then invalid("actor must be a valid DID") end - local function valid_nsid(value) - if type(value) ~= "string" or #value > 317 then return false end - local segments = {} - for segment in value:gmatch("[^%.]+") do segments[#segments + 1] = segment end - if #segments < 3 or table.concat(segments, ".") ~= value then return false end - - for _, segment in ipairs(segments) do - if #segment > 63 or segment:find("[^A-Za-z0-9%-]") - or segment:sub(1, 1) == "-" or segment:sub(-1) == "-" then - return false - end - end - - if not segments[1]:sub(1, 1):match("^[A-Za-z]$") then return false end - return segments[#segments]:match("^[A-Za-z][A-Za-z0-9]*$") ~= nil - end - local function valid_entity_uri(value) if #value > 8192 then return false end local valid, collection = valid_record_uri(value) diff --git a/happyview-modules/lua/src/getReactionCounts.lua b/happyview-modules/lua/src/getReactionCounts.lua index 369219d1..8187425e 100644 --- a/happyview-modules/lua/src/getReactionCounts.lua +++ b/happyview-modules/lua/src/getReactionCounts.lua @@ -14,22 +14,6 @@ local function reaction_count_valid_did_percent_escapes(authority) return true end -local function reaction_count_valid_nsid(value) - if type(value) ~= "string" or #value > 317 then return false end - local segments = {} - for segment in value:gmatch("[^%.]+") do segments[#segments + 1] = segment end - if #segments < 3 or table.concat(segments, ".") ~= value then return false end - for index = 1, #segments - 1 do - local segment = segments[index] - if #segment > 63 or segment:find("[^A-Za-z0-9%-]") then return false end - local first, last = segment:sub(1, 1), segment:sub(-1) - if not first:match(index == 1 and "^[A-Za-z]$" or "^[A-Za-z0-9]$") - or not last:match("^[A-Za-z0-9]$") then return false end - end - local name = segments[#segments] - return #name <= 63 and name:match("^[A-Za-z][A-Za-z0-9]*$") ~= nil -end - local function reaction_count_subjects() local value = params.subjects if value == nil then invalid("subjects is required") end @@ -63,7 +47,7 @@ local function reaction_count_subjects() for _, subject in ipairs(supplied) do local valid, collection, authority = valid_record_uri(subject) if not valid or not reaction_count_valid_did_percent_escapes(authority) - or not reaction_count_valid_nsid(collection) then + or not valid_nsid(collection) then invalid("each subjects value must be a full AT-URI with a valid DID authority and collection NSID") end if not seen[subject] then diff --git a/happyview-modules/lua/src/listBadgeAwards.lua b/happyview-modules/lua/src/listBadgeAwards.lua index 79b2adbb..0ec48fec 100644 --- a/happyview-modules/lua/src/listBadgeAwards.lua +++ b/happyview-modules/lua/src/listBadgeAwards.lua @@ -13,22 +13,6 @@ local function valid_badge_definition_uri(value) return valid and collection == DEFINITION end -local function valid_badge_subject_nsid(value) - if type(value) ~= "string" or #value > 317 then return false end - local segments = {} - for segment in value:gmatch("[^%.]+") do segments[#segments + 1] = segment end - if #segments < 3 or table.concat(segments, ".") ~= value then return false end - for index = 1, #segments - 1 do - local segment = segments[index] - if #segment > 63 or segment:find("[^A-Za-z0-9%-]") then return false end - local first, last = segment:sub(1, 1), segment:sub(-1) - if not first:match(index == 1 and "^[A-Za-z]$" or "^[A-Za-z0-9]$") - or not last:match("^[A-Za-z0-9]$") then return false end - end - local name = segments[#segments] - return #name <= 63 and name:match("^[A-Za-z][A-Za-z0-9]*$") ~= nil -end - local function query(sql, values) if db.backend() ~= "postgres" then error("BadgeAwardQueryFailed: badge award API requires PostgreSQL", 0) @@ -80,7 +64,7 @@ local function subject_values() local is_did = valid_did(item) local valid_uri, collection if not is_did then valid_uri, collection = valid_record_uri(item) end - if not is_did and (not valid_uri or not valid_badge_subject_nsid(collection)) then + if not is_did and (not valid_uri or not valid_nsid(collection)) then invalid("subjects[" .. index .. "] must be a valid DID or full record AT-URI with a valid collection NSID") end if not seen[item] then diff --git a/happyview-modules/lua/src/listMeasurements.lua b/happyview-modules/lua/src/listMeasurements.lua index 053dc79d..5f6143f1 100644 --- a/happyview-modules/lua/src/listMeasurements.lua +++ b/happyview-modules/lua/src/listMeasurements.lua @@ -1,23 +1,3 @@ -local function valid_nsid(value) - if type(value) ~= "string" or #value > 317 then return false end - local segments = {} - for segment in value:gmatch("[^%.]+") do segments[#segments + 1] = segment end - if #segments < 3 or table.concat(segments, ".") ~= value then return false end - - for index = 1, #segments - 1 do - local segment = segments[index] - if #segment > 63 or segment:find("[^A-Za-z0-9%-]") then return false end - local first, last = segment:sub(1, 1), segment:sub(-1) - if not first:match(index == 1 and "^[A-Za-z]$" or "^[A-Za-z0-9]$") - or not last:match("^[A-Za-z0-9]$") then - return false - end - end - - local name = segments[#segments] - return #name <= 63 and name:match("^[A-Za-z][A-Za-z0-9]*$") ~= nil -end - local function measurement_array(key, format) local value = params[key] if value == nil then return nil end diff --git a/happyview-modules/modules/acknowledgements/manifest.json b/happyview-modules/modules/acknowledgements/manifest.json index 847e4231..4ae64fd3 100644 --- a/happyview-modules/modules/acknowledgements/manifest.json +++ b/happyview-modules/modules/acknowledgements/manifest.json @@ -67,6 +67,7 @@ "../../lua/shared/datetimeValidation.lua", "../../lua/shared/listValidation.lua", "../../lua/shared/acknowledgement.lua", + "../../lua/shared/nsidValidation.lua", "../../lua/shared/acknowledgementList.lua" ], "config": { diff --git a/happyview-modules/modules/badge-queries/manifest.json b/happyview-modules/modules/badge-queries/manifest.json index d9094381..04b597b8 100644 --- a/happyview-modules/modules/badge-queries/manifest.json +++ b/happyview-modules/modules/badge-queries/manifest.json @@ -107,7 +107,8 @@ "../../lua/shared/listValidation.lua", "../../lua/shared/listQuery.lua", "../../lua/shared/recordView.lua", - "../../lua/shared/actorView.lua" + "../../lua/shared/actorView.lua", + "../../lua/shared/nsidValidation.lua" ], "config": { "script_type": "lua", diff --git a/happyview-modules/modules/context-evaluation/manifest.json b/happyview-modules/modules/context-evaluation/manifest.json index 88ed89a6..e0b0c434 100644 --- a/happyview-modules/modules/context-evaluation/manifest.json +++ b/happyview-modules/modules/context-evaluation/manifest.json @@ -54,6 +54,7 @@ "../../lua/shared/recordView.lua", "../../lua/shared/actorView.lua", "../../lua/shared/evaluation.lua", + "../../lua/shared/nsidValidation.lua", "../../lua/shared/evaluationList.lua" ], "config": { diff --git a/happyview-modules/modules/context-measurements/manifest.json b/happyview-modules/modules/context-measurements/manifest.json index 8bc0c670..99a5e3b7 100644 --- a/happyview-modules/modules/context-measurements/manifest.json +++ b/happyview-modules/modules/context-measurements/manifest.json @@ -53,7 +53,8 @@ "../../lua/shared/listQuery.lua", "../../lua/shared/recordView.lua", "../../lua/shared/actorView.lua", - "../../lua/shared/measurementQuery.lua" + "../../lua/shared/measurementQuery.lua", + "../../lua/shared/nsidValidation.lua" ], "config": { "script_type": "lua" diff --git a/happyview-modules/modules/entity-follow/manifest.json b/happyview-modules/modules/entity-follow/manifest.json index 870ea335..b9af0b0d 100644 --- a/happyview-modules/modules/entity-follow/manifest.json +++ b/happyview-modules/modules/entity-follow/manifest.json @@ -73,7 +73,8 @@ "../../lua/shared/query.lua", "../../lua/shared/recordIdentifier.lua", "../../lua/shared/entityFollow.lua", - "../../lua/shared/followBatch.lua" + "../../lua/shared/followBatch.lua", + "../../lua/shared/nsidValidation.lua" ], "config": { "script_type": "lua", diff --git a/happyview-modules/modules/feed-reactions/manifest.json b/happyview-modules/modules/feed-reactions/manifest.json index 905d2513..ecb0b51c 100644 --- a/happyview-modules/modules/feed-reactions/manifest.json +++ b/happyview-modules/modules/feed-reactions/manifest.json @@ -142,6 +142,7 @@ "../../lua/shared/query.lua", "../../lua/shared/recordIdentifier.lua", "../../lua/shared/recordView.lua", + "../../lua/shared/nsidValidation.lua", "../../lua/shared/feedActorReactions.lua" ], "config": { "script_type": "lua", "description": "Actor feed reaction API handler" }, @@ -155,7 +156,8 @@ "sharedSourcePaths": [ "../../lua/shared/didValidation.lua", "../../lua/shared/query.lua", - "../../lua/shared/recordIdentifier.lua" + "../../lua/shared/recordIdentifier.lua", + "../../lua/shared/nsidValidation.lua" ], "config": { "script_type": "lua", diff --git a/happyview-modules/modules/funding/manifest.json b/happyview-modules/modules/funding/manifest.json index dfb6e92b..a1dae3f8 100644 --- a/happyview-modules/modules/funding/manifest.json +++ b/happyview-modules/modules/funding/manifest.json @@ -53,6 +53,7 @@ "../../lua/shared/recordView.lua", "../../lua/shared/actorView.lua", "../../lua/shared/fundingReceipt.lua", + "../../lua/shared/nsidValidation.lua", "../../lua/shared/fundingReceiptList.lua" ], "config": {