You cannot select more than 25 topics
			Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
		
		
		
		
		
			
		
			
				
	
	
		
			113 lines
		
	
	
		
			2.9 KiB
		
	
	
	
		
			TypeScript
		
	
			
		
		
	
	
			113 lines
		
	
	
		
			2.9 KiB
		
	
	
	
		
			TypeScript
		
	
import { createHash } from 'crypto';
 | 
						|
import {
 | 
						|
  createReadStream,
 | 
						|
  readFile as readFileCallback,
 | 
						|
  writeFile as writeFileCallback,
 | 
						|
} from 'fs';
 | 
						|
import { basename, dirname, join, resolve as resolvePath } from 'path';
 | 
						|
 | 
						|
import pify from 'pify';
 | 
						|
 | 
						|
import { BinaryType, sign, verify } from './curve';
 | 
						|
 | 
						|
const readFile = pify(readFileCallback);
 | 
						|
const writeFile = pify(writeFileCallback);
 | 
						|
 | 
						|
export async function generateSignature(
 | 
						|
  updatePackagePath: string,
 | 
						|
  version: string,
 | 
						|
  privateKeyPath: string
 | 
						|
) {
 | 
						|
  const privateKey = await loadHexFromPath(privateKeyPath);
 | 
						|
  const message = await generateMessage(updatePackagePath, version);
 | 
						|
 | 
						|
  return sign(privateKey, message);
 | 
						|
}
 | 
						|
 | 
						|
export async function verifySignature(
 | 
						|
  updatePackagePath: string,
 | 
						|
  version: string,
 | 
						|
  publicKey: BinaryType
 | 
						|
): Promise<boolean> {
 | 
						|
  const signaturePath = getSignaturePath(updatePackagePath);
 | 
						|
  const signature = await loadHexFromPath(signaturePath);
 | 
						|
  const message = await generateMessage(updatePackagePath, version);
 | 
						|
 | 
						|
  return verify(publicKey, message, signature);
 | 
						|
}
 | 
						|
 | 
						|
// Helper methods
 | 
						|
 | 
						|
async function generateMessage(
 | 
						|
  updatePackagePath: string,
 | 
						|
  version: string
 | 
						|
): Promise<BinaryType> {
 | 
						|
  const hash = await _getFileHash(updatePackagePath);
 | 
						|
  const messageString = `${Buffer.from(hash).toString('hex')}-${version}`;
 | 
						|
 | 
						|
  return Buffer.from(messageString);
 | 
						|
}
 | 
						|
 | 
						|
export async function writeSignature(
 | 
						|
  updatePackagePath: string,
 | 
						|
  version: string,
 | 
						|
  privateKeyPath: string
 | 
						|
) {
 | 
						|
  const signaturePath = getSignaturePath(updatePackagePath);
 | 
						|
  const signature = await generateSignature(
 | 
						|
    updatePackagePath,
 | 
						|
    version,
 | 
						|
    privateKeyPath
 | 
						|
  );
 | 
						|
  await writeHexToPath(signaturePath, signature);
 | 
						|
}
 | 
						|
 | 
						|
export async function _getFileHash(
 | 
						|
  updatePackagePath: string
 | 
						|
): Promise<BinaryType> {
 | 
						|
  const hash = createHash('sha256');
 | 
						|
  const stream = createReadStream(updatePackagePath);
 | 
						|
 | 
						|
  return new Promise((resolve, reject) => {
 | 
						|
    stream.on('data', data => {
 | 
						|
      hash.update(data);
 | 
						|
    });
 | 
						|
    stream.on('close', () => {
 | 
						|
      resolve(hash.digest());
 | 
						|
    });
 | 
						|
    stream.on('error', error => {
 | 
						|
      reject(error);
 | 
						|
    });
 | 
						|
  });
 | 
						|
}
 | 
						|
 | 
						|
export function getSignatureFileName(fileName: string) {
 | 
						|
  return `${fileName}.sig`;
 | 
						|
}
 | 
						|
 | 
						|
export function getSignaturePath(updatePackagePath: string): string {
 | 
						|
  const updateFullPath = resolvePath(updatePackagePath);
 | 
						|
  const updateDir = dirname(updateFullPath);
 | 
						|
  const updateFileName = basename(updateFullPath);
 | 
						|
 | 
						|
  return join(updateDir, getSignatureFileName(updateFileName));
 | 
						|
}
 | 
						|
 | 
						|
export function hexToBinary(target: string): BinaryType {
 | 
						|
  return Buffer.from(target, 'hex');
 | 
						|
}
 | 
						|
 | 
						|
export function binaryToHex(data: BinaryType): string {
 | 
						|
  return Buffer.from(data).toString('hex');
 | 
						|
}
 | 
						|
 | 
						|
export async function loadHexFromPath(target: string): Promise<BinaryType> {
 | 
						|
  const hexString = await readFile(target, 'utf8');
 | 
						|
 | 
						|
  return hexToBinary(hexString);
 | 
						|
}
 | 
						|
 | 
						|
export async function writeHexToPath(target: string, data: BinaryType) {
 | 
						|
  await writeFile(target, binaryToHex(data));
 | 
						|
}
 |