github.com/google/trillian-examples@v0.0.0-20240520080811-0d40d35cef0e/binary_transparency/firmware/cmd/ft_personality/internal/cas/sql.go (about)

     1  // Copyright 2020 Google LLC. All Rights Reserved.
     2  //
     3  // Licensed under the Apache License, Version 2.0 (the "License");
     4  // you may not use this file except in compliance with the License.
     5  // You may obtain a copy of the License at
     6  //
     7  //     http://www.apache.org/licenses/LICENSE-2.0
     8  //
     9  // Unless required by applicable law or agreed to in writing, software
    10  // distributed under the License is distributed on an "AS IS" BASIS,
    11  // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    12  // See the License for the specific language governing permissions and
    13  // limitations under the License.
    14  
    15  // Package cas contains a Content Addressable Store.
    16  package cas
    17  
    18  import (
    19  	"database/sql"
    20  
    21  	"google.golang.org/grpc/codes"
    22  	"google.golang.org/grpc/status"
    23  )
    24  
    25  // BinaryStorage is a CAS intended for storing binary images keyed by their hash string
    26  // that uses a SQL Database as its backing store.
    27  type BinaryStorage struct {
    28  	db *sql.DB
    29  }
    30  
    31  // NewBinaryStorage creates a new CAS that uses the given DB as a backend.
    32  // The DB will be initialized if needed.
    33  func NewBinaryStorage(db *sql.DB) (*BinaryStorage, error) {
    34  	cas := &BinaryStorage{
    35  		db: db,
    36  	}
    37  	return cas, cas.init()
    38  }
    39  
    40  // init creates the database tables if needed.
    41  func (bs *BinaryStorage) init() error {
    42  	_, err := bs.db.Exec("CREATE TABLE IF NOT EXISTS images (key BLOB PRIMARY KEY, data BLOB)")
    43  	return err
    44  }
    45  
    46  // Store stores a binary image under the given key (which should be a hash of its data).
    47  // If there was an existing value under the key then it will not be updated.
    48  // TODO(mhutchinson): Consider validating that the image is exactly the same if the key
    49  // already exists. This should only happen if the hash function isn't strong.
    50  func (bs *BinaryStorage) Store(key, image []byte) error {
    51  	_, err := bs.db.Exec("INSERT OR IGNORE INTO images (key, data) VALUES (?, ?)", key, image)
    52  	return err
    53  }
    54  
    55  // Retrieve gets a binary image that was previously stored.
    56  func (bs *BinaryStorage) Retrieve(key []byte) ([]byte, error) {
    57  	var res []byte
    58  	row := bs.db.QueryRow("SELECT data FROM images WHERE key=?", key)
    59  	if err := row.Err(); err != nil {
    60  		return nil, err
    61  	}
    62  
    63  	if err := row.Scan(&res); err != nil {
    64  		if err == sql.ErrNoRows {
    65  			return nil, status.Errorf(codes.NotFound, "unknown hash: %q", err)
    66  		}
    67  		return nil, err
    68  
    69  	}
    70  	return res, nil
    71  }