NAME
PowerDNS::API::ACL::Store - The tokens and grants of PowerDNS::API::ACL, kept in SQLite
VERSION
version 0.001
SYNOPSIS
my $store = PowerDNS::API::ACL::Store->new( path => '/var/lib/pdns-acl/acl.db' );
my $secret = $store->add_token(
'web1',
{ zone => 'lab.example.net.', name => 'web1.lab.example.net.', types => [qw{A AAAA}], access => 'write' },
{ zone => 'lab.example.net.', name => '*.web1.lab.example.net.', access => 'write' },
);
DESCRIPTION
A token is a random secret that a client presents as its API key. The store keeps only an HMAC-SHA-256 of each secret, keyed with a random salt that the database makes when it is created. So a copy of the database does not give anybody a working key, and a digest from one database means nothing in another. add_token returns the secret once, and nothing can show it again.
Each token has a label, which is how an operator names it, and at least one grant. A token with no grant could do nothing, so the store does not make one, and does not remove the last grant of a token. Remove the token instead. PowerDNS::API::ACL says what a grant means.
METHODS
new(path => $path)
Opens the database at $path. If it is new, creates its tables and its salt.
The proxy and pdns-acl each open the database, and more than one of them can write at once. So the database is in WAL mode, and a connection waits up to five seconds for a lock before it gives up. Dies when SQLite will not use WAL, as for a database in memory.
dbh()
Returns the connection to the database, and opens it first if this process has none.
A PSGI server that forks its workers after it loads the application would otherwise hand each worker the connection of its parent, and SQLite forbids a connection that two processes use. So the store remembers the process that opened its connection, and a forked process opens its own.
digest($secret)
Returns the digest that the database keeps for $secret.
add_token($label, @grants)
Makes a token with this label and these grants, and returns its secret. Each grant is a hash reference, as add_grant takes it.
Dies when the label is taken, when there is no grant, or when a grant is invalid. Then it makes nothing.
remove_token($label)
Removes the token and its grants. Returns true when there was one.
tokens()
Returns each token as a hash reference of label, created (epoch seconds) and grants (how many), sorted by label.
token_id($label)
Returns the row id of the token with this label, or undef.
add_grant($label, zone => $zone, name => $name, types => \@types, access => $access)
Adds a grant to the token with this label. types defaults to ['*'].
access is read, write or manage. A manage grant is for the zone itself, so its name is the zone, and is the zone when left out, and its types are *.
Dies when there is no such token, when access is none of those, or when name is not in zone. A name pattern is checked without its *., so *.lab.example.net. is in lab.example.net..
remove_grant($id)
Removes the grant with this row id, as grants reports it. Returns true when there was one. Dies when it is the last grant of its token.
grants($label)
Returns the grants of the token with this label, each as a hash reference of id, zone, name, types (an array reference) and access.
grants_for_token($secret)
Returns the grants of the token whose secret this is, as grants does, or nothing when no token has this secret. PowerDNS::API::ACL asks this for each request.
select_grants($sql, @bind)
Runs a query that selects the columns of a grant, and returns each row as grants describes it.
transaction($code)
Runs $code in one transaction, and rolls it back if $code dies. Dies with what $code died with.
DBD::SQLite begins a transaction with BEGIN IMMEDIATE, which takes the write lock at once. So $code can read and then write without another writer in between, and the wait for the lock is the busy_timeout.
SEE ALSO
Please see those modules/websites for more information related to this module.
BUGS
Please report any bugs or feature requests on the bugtracker website https://github.com/Troglodyne-Internet-Widgets/perl-powerdns-api-acl/issues
When submitting a bug or request, please include a test-file or a patch to an existing test-file that illustrates the bug or desired feature.
AUTHORS
Current Maintainers:
George S. Baugh <george@troglodyne.net>
COPYRIGHT AND LICENSE
Copyright (c) 2026 Troglodyne LLC
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.