import { Validator } from "./Validator" ; import { IPv4 , IPv4Mask , IPv6 , IPv6Mask } from "./IPNumber" ; import { intLog2 , parseBinaryStringToBigInteger } from "./BinaryUtils" ; import { IPNumType } from "./IPNumType" ; import { binaryStringToHexadecimalString } from "./HexadecimalUtils" ; import { Hexadecatet } from "./Hexadecatet" ; import * as bigInt from "big-integer" ; interface Prefix { value : number ; getValue ( ) : number ; merge ( ) : Prefix ; split ( ) : Prefix ; toString ( ) : string ; toRangeSize ( ) : bigInt . BigInteger ; } /**
 * Represents the prefix portion in the CIDR notation for representing IP ranges
 *
 * The IPv4 prefix portion represents the mask. It is the number of continuous bits turned on (with value 1)
 * counting from the left side of an 8 bit value.
 *
 * {@see https://en.wikipedia.org/wiki/Classless_Inter-Domain_Routing} for more information on CIDR
 */ class IPv4Prefix implements Prefix { type : "IPv4" = "IPv4" ; private readonly bitValue : bigInt . BigInteger = bigInt ( 32 ) ; /**
     * The decimal value of the 8bit number representing the prefix
     */ value : number ; param { number } rawValue returns { IPv4Prefix } static fromNumber ( rawValue ) { return new IPv4Prefix ( rawValue ) ; } ; static fromRangeSize ( rangeSize ) { let prefixNumber = rangeSize . equals ( bigInt . one ) ? 32 : 32 - rangeSizeToPrefix ( rangeSize , Validator . IPV4_SIZE ) ; return IPv4Prefix . fromNumber ( prefixNumber ) ; } ; param { number } rawValue returns { IPv4Prefix } constructor ( rawValue ) { let isValid ; let message ; [ isValid , message ] = Validator . isValidPrefixValue ( rawValue , IPNumType . IPv4 ) ; if ( ! isValid ) { throw new Error ( message . filter ( msg => { return msg !== '' ; } ) . toString ( ) ) ; } this . value = rawValue ; } returns { number } public getValue ( ) { return this . value ; } returns { string } public toString ( ) { return this . value . toString ( ) ; } /**
     * Converts the IPv4 prefix to a  IPv4Mask *
     * The IPv4 mask is the representation of the prefix in the dot-decimal notation
     *
     *  returns { IPv4Mask } public toMask ( ) { let onBits = '1' . repeat ( this . value ) ; let offBits = '0' . repeat ( 32 - this . value ) ; return IPv4Mask . fromDecimalDottedString ( this . toDecimalNotation ( `${ onBits }${ offBits }` ) ) ; } return { BigInteger } public toRangeSize ( ) { /**
         * Using bitwise shift operation this will be
         * 1 << (this.bitValue - this.prefix.getValue())
         * Since left shift a number by x is equivalent to multiplying the number by the power x raised to 2
         * 2 << 4 = 2 * (2 raised to 4)
         */ return bigInt ( 2 ) . pow ( this . bitValue . minus ( bigInt ( this . getValue ( ) ) ) ) ; } /**
     * Returns a prefix for when this prefix is merged
     * with another prefix of the same size
     */ merge ( ) { return new IPv4Prefix ( this . value - 1 ) ; } /**
     * Returns a prefix for when this prefix is split
     * into two equal halves
     */ split ( ) { return new IPv4Prefix ( this . value + 1 ) ; } private toDecimalNotation ( bits ) { return `${ parseBinaryStringToBigInteger ( bits . substr ( 0 , 8 ) ) }.${ parseBinaryStringToBigInteger ( bits . substr ( 8 , 8 ) ) }.${ parseBinaryStringToBigInteger ( bits . substr ( 16 , 8 ) ) }.${ parseBinaryStringToBigInteger ( bits . substr ( 24 , 8 ) ) }` ; } } /**
 * Represents the prefix portion in the CIDR notation for representing IP ranges
 *
 * The IPv6 prefix portion represents the mask. It is the number of continuous bits turned on (with value 1)
 * counting from the left side of an 128 bit value.
 *
 * {@see https://en.wikipedia.org/wiki/Classless_Inter-Domain_Routing} for more information on CIDR
 */ class IPv6Prefix implements Prefix { type : "IPv6" = "IPv6" ; private readonly bitValue : bigInt . BigInteger = bigInt ( 128 ) ; /**
     * The decimal value of the 16bit number representing the prefix
     */ value : number ; param { number } rawValue returns { IPv4Prefix } static fromNumber ( rawValue ) { return new IPv6Prefix ( rawValue ) ; } ; static fromRangeSize ( rangeSize ) { let prefixNumber = rangeSize . equals ( bigInt . one ) ? 128 : 128 - rangeSizeToPrefix ( rangeSize , Validator . IPV6_SIZE ) ; return IPv6Prefix . fromNumber ( prefixNumber ) ; } param { number } rawValue returns { IPv4Prefix } constructor ( rawValue ) { let isValid ; let message ; [ isValid , message ] = Validator . isValidPrefixValue ( rawValue , IPNumType . IPv6 ) ; if ( ! isValid ) { throw new Error ( message . filter ( msg => { return msg !== '' ; } ) . toString ( ) ) ; } this . value = rawValue ; } returns { number } public getValue ( ) { return this . value ; } returns { string } public toString ( ) { return this . value . toString ( ) ; } /**
     * Converts the IPv6 prefix to a  IPv6Mask *
     * The IPv6 mask is the representation of the prefix in 8 groups of 16 bit values represented in hexadecimal
     *
     *  returns { IPv6Mask } public toMask ( ) { let onBits = '1' . repeat ( this . value ) ; let offBits = '0' . repeat ( 128 - this . value ) ; return IPv6Mask . fromHexadecimalString ( this . toHexadecatetNotation ( `${ onBits }${ offBits }` ) ) ; } return { BigInteger } public toRangeSize ( ) { /**
         * Using bitwise shift operation this will be
         * 1 << (this.bitValue - this.prefix.getValue())
         * Since left shift a number by x is equivalent to multiplying the number by the power x raised to 2
         * 2 << 4 = 2 * (2 raised to 4)
         */ return bigInt ( 2 ) . pow ( this . bitValue . minus ( bigInt ( this . getValue ( ) ) ) ) ; } /**
     * Returns a prefix for when this prefix is merged
     * with another prefix of the same size
     */ merge ( ) { return new IPv6Prefix ( this . value - 1 ) ; } /**
     * Returns a prefix for when this prefix is split
     * into two equal halves
     */ split ( ) { return new IPv6Prefix ( this . value + 1 ) ; } private toHexadecatetNotation ( bits ) { let binaryStrings = bits . match ( /.{1,16}/g ) ! ; let hexadecimalStrings = binaryStrings . map ( ( binaryString ) => { return Hexadecatet . fromString ( binaryStringToHexadecimalString ( binaryString ) ) ; } ) ; return hexadecimalStrings . map ( ( value ) => { return value . toString ( ) ; } ) . join ( ":" ) ; } } function rangeSizeToPrefix ( rangeSize , rangeMaxSize ) { let ipType = rangeMaxSize . greater ( Validator . IPV4_SIZE ) ? "IPv6" : "IPv4" ; if ( rangeSize . greater ( rangeMaxSize ) || rangeSize . equals ( bigInt ( 0 ) ) ) { throw new Error ( Validator . invalidIPRangeSizeMessage . replace ( "$iptype" , ipType ) ) ; } try { return intLog2 ( rangeSize ) ; } catch ( e ) { throw new Error ( Validator . invalidIPRangeSizeForCidrMessage ) ; } } /**
 * Check is the given Prefix is an  IPv4Prefix or not
 *  param prefix function isIPv4Prefix ( prefix ) { return prefix . type === "IPv4" ; } /**
 * Check is the given Prefix is an  IPv4Prefix or not
 *  param prefix function isIPv6Prefix ( prefix ) { return prefix . type === "IPv6" ; } export { Prefix , IPv4Prefix , IPv6Prefix , isIPv4Prefix } ;