From ac2daed4daac86b85db53af82ea6eadb47b4c941 Mon Sep 17 00:00:00 2001 From: Steven Miers Date: Sun, 14 Dec 2014 19:42:38 -0600 Subject: [PATCH] VRFS-2481 : Jam Tracks python layer and source. --- ruby/bin/jamtrack.rb | 1 + ruby/lib/jam_ruby.rb | 2 + .../app/uploaders/jam_track_right_uploader.rb | 28 ++ ruby/lib/jam_ruby/jam_tracks_manager.rb | 22 + ruby/lib/jam_ruby/models/jam_track_right.rb | 12 +- ruby/lib/py/jam_tracks/jamtrack.info | 1 + ruby/lib/py/jam_tracks/jamtracklist.txt | 8 + ruby/lib/py/jam_tracks/jkaes.py | 212 +++++++++ ruby/lib/py/jam_tracks/jkaes.pyc | Bin 0 -> 9156 bytes ruby/lib/py/jam_tracks/jkasset.py | 431 ++++++++++++++++++ ruby/lib/py/jam_tracks/jkasset.pyc | Bin 0 -> 11420 bytes ruby/lib/py/jam_tracks/jkcreate.py | 249 ++++++++++ ruby/lib/py/jam_tracks/jkmedia.py | 44 ++ ruby/lib/py/jam_tracks/jkrsa.py | 194 ++++++++ ruby/lib/py/jam_tracks/jktrack.py | 104 +++++ ruby/lib/py/jam_tracks/jktrack.pyc | Bin 0 -> 5712 bytes ruby/lib/py/jam_tracks/jkunpack.py | 56 +++ ruby/lib/py/jam_tracks/jkzify.rb | 98 ++++ 18 files changed, 1461 insertions(+), 1 deletion(-) create mode 100644 ruby/bin/jamtrack.rb create mode 100644 ruby/lib/jam_ruby/app/uploaders/jam_track_right_uploader.rb create mode 100644 ruby/lib/jam_ruby/jam_tracks_manager.rb create mode 100644 ruby/lib/py/jam_tracks/jamtrack.info create mode 100644 ruby/lib/py/jam_tracks/jamtracklist.txt create mode 100755 ruby/lib/py/jam_tracks/jkaes.py create mode 100644 ruby/lib/py/jam_tracks/jkaes.pyc create mode 100755 ruby/lib/py/jam_tracks/jkasset.py create mode 100644 ruby/lib/py/jam_tracks/jkasset.pyc create mode 100755 ruby/lib/py/jam_tracks/jkcreate.py create mode 100644 ruby/lib/py/jam_tracks/jkmedia.py create mode 100755 ruby/lib/py/jam_tracks/jkrsa.py create mode 100755 ruby/lib/py/jam_tracks/jktrack.py create mode 100644 ruby/lib/py/jam_tracks/jktrack.pyc create mode 100755 ruby/lib/py/jam_tracks/jkunpack.py create mode 100755 ruby/lib/py/jam_tracks/jkzify.rb diff --git a/ruby/bin/jamtrack.rb b/ruby/bin/jamtrack.rb new file mode 100644 index 000000000..2152352db --- /dev/null +++ b/ruby/bin/jamtrack.rb @@ -0,0 +1 @@ +{"SKU": "0044454545454", "METADATA_VER": 1, "TrackData": {"track_2": {"length": 0.1, "bitrate": 96000}, "track_1": {"length": 264.5681632653061, "bitrate": 128003}, "track_0": {"length": 405.054693877551, "bitrate": 128003}}, "TrackInstrument": {"track_1": "Alto Sax", "track_0": "Bass Guitar"}, "Title": "SmFtS2F6YW0gcm9sbGluZyBpbiB0aGUgZG91Z2g="} \ No newline at end of file diff --git a/ruby/lib/jam_ruby.rb b/ruby/lib/jam_ruby.rb index 07234042f..b3b1a3ee1 100755 --- a/ruby/lib/jam_ruby.rb +++ b/ruby/lib/jam_ruby.rb @@ -74,6 +74,7 @@ require "jam_ruby/app/uploaders/mix_uploader" require "jam_ruby/app/uploaders/music_notation_uploader" require "jam_ruby/app/uploaders/jam_track_uploader" require "jam_ruby/app/uploaders/jam_track_track_uploader" +require "jam_ruby/app/uploaders/jam_track_right_uploader" require "jam_ruby/app/uploaders/max_mind_release_uploader" require "jam_ruby/lib/desk_multipass" require "jam_ruby/lib/ip" @@ -189,6 +190,7 @@ require "jam_ruby/models/jam_company" require "jam_ruby/models/user_sync" require "jam_ruby/models/video_source" require "jam_ruby/models/recorded_video" +require "jam_ruby/jam_tracks_manager" include Jampb diff --git a/ruby/lib/jam_ruby/app/uploaders/jam_track_right_uploader.rb b/ruby/lib/jam_ruby/app/uploaders/jam_track_right_uploader.rb new file mode 100644 index 000000000..e33494063 --- /dev/null +++ b/ruby/lib/jam_ruby/app/uploaders/jam_track_right_uploader.rb @@ -0,0 +1,28 @@ +class JamTrackRightUploader < CarrierWave::Uploader::Base + # include CarrierWaveDirect::Uploader + include CarrierWave::MimeTypes + + process :set_content_type + + def initialize(*) + super + JamRuby::UploaderConfiguration.set_aws_private_configuration(self) + end + + # Add a white list of extensions which are allowed to be uploaded. + def extension_white_list + %w(jkz) + end + + def store_dir + nil + end + + def md5 + @md5 ||= ::Digest::MD5.file(current_path).hexdigest + end + + def filename + "#{model.store_dir}/#{model.filename}" if model.id + end +end diff --git a/ruby/lib/jam_ruby/jam_tracks_manager.rb b/ruby/lib/jam_ruby/jam_tracks_manager.rb new file mode 100644 index 000000000..07b264df0 --- /dev/null +++ b/ruby/lib/jam_ruby/jam_tracks_manager.rb @@ -0,0 +1,22 @@ +module JamRuby + + # describes an audio track (like the drums, or guitar) that comprises a JamTrack + class JamTracksManager + class << self + def save_jam_track(jam_track, user) + spec = Gem::Specification.find_by_name("jam_ruby") + py_root = spec.gem_dir + "/lib/py/jam_tracks/" + puts "Executing python in #{py_root}" + + sku=""#jam_track.sku + public_key="" + private_key="" + tracks_filename="" + output_jkz="" + title="" + `python #{py_root}jkcreate.py -D -k #{sku} -c art.png -p #{public_key} -s #{private_key} -I #{tracks_filename} -o #{output_jkz} -t '#{title}'` + end + end + end + +end diff --git a/ruby/lib/jam_ruby/models/jam_track_right.rb b/ruby/lib/jam_ruby/models/jam_track_right.rb index 57c0a444f..33a036a05 100644 --- a/ruby/lib/jam_ruby/models/jam_track_right.rb +++ b/ruby/lib/jam_ruby/models/jam_track_right.rb @@ -2,7 +2,7 @@ module JamRuby # describes what users have rights to which tracks class JamTrackRight < ActiveRecord::Base - attr_accessible :user, :jam_track, :user_id, :jam_track_id + attr_accessible :user, :jam_track, :user_id, :jam_track_id, :url, :md5, :length, :download_count belongs_to :user, class_name: "JamRuby::User" # the owner, or purchaser of the jam_track belongs_to :jam_track, class_name: "JamRuby::JamTrack" @@ -11,6 +11,10 @@ module JamRuby validate :verify_download_count validates_uniqueness_of :user_id, scope: :jam_track_id + + # Uploads the JKZ: + mount_uploader :url, JamTrackRightUploader + MAX_JAM_TRACK_DOWNLOADS = 1000 def verify_download_count @@ -18,5 +22,11 @@ module JamRuby errors.add(:download_count, "must be less than or equal to #{MAX_JAM_TRACK_DOWNLOADS}") end end + + # Create user-specific JKZ for the associated jam_track: + def create_jkz + + end + end end diff --git a/ruby/lib/py/jam_tracks/jamtrack.info b/ruby/lib/py/jam_tracks/jamtrack.info new file mode 100644 index 000000000..2152352db --- /dev/null +++ b/ruby/lib/py/jam_tracks/jamtrack.info @@ -0,0 +1 @@ +{"SKU": "0044454545454", "METADATA_VER": 1, "TrackData": {"track_2": {"length": 0.1, "bitrate": 96000}, "track_1": {"length": 264.5681632653061, "bitrate": 128003}, "track_0": {"length": 405.054693877551, "bitrate": 128003}}, "TrackInstrument": {"track_1": "Alto Sax", "track_0": "Bass Guitar"}, "Title": "SmFtS2F6YW0gcm9sbGluZyBpbiB0aGUgZG91Z2g="} \ No newline at end of file diff --git a/ruby/lib/py/jam_tracks/jamtracklist.txt b/ruby/lib/py/jam_tracks/jamtracklist.txt new file mode 100644 index 000000000..6fa0a517d --- /dev/null +++ b/ruby/lib/py/jam_tracks/jamtracklist.txt @@ -0,0 +1,8 @@ +You Shook Me All Night Long/You Shook Me All Night Long Stem - Bass.ogg+Bass +You Shook Me All Night Long/You Shook Me All Night Long Stem - Drums.ogg+Drums +You Shook Me All Night Long/You Shook Me All Night Long Stem - Guitar - Main.ogg+Guitar Main +You Shook Me All Night Long/You Shook Me All Night Long Stem - Guitar - Rhythm 2.ogg+Guitar Rhythm 2 +You Shook Me All Night Long/You Shook Me All Night Long Stem - Guitar - Rhythm.ogg+Guitar Rhythm +You Shook Me All Night Long/You Shook Me All Night Long Stem - Guitar - Solo.ogg+Guitar Solo +You Shook Me All Night Long/You Shook Me All Night Long Stem - Vocals - Background.ogg+Vocals Background +You Shook Me All Night Long/You Shook Me All Night Long Stem - Vocals - Lead.ogg+Vocals Lead diff --git a/ruby/lib/py/jam_tracks/jkaes.py b/ruby/lib/py/jam_tracks/jkaes.py new file mode 100755 index 000000000..49966001f --- /dev/null +++ b/ruby/lib/py/jam_tracks/jkaes.py @@ -0,0 +1,212 @@ +#!/usr/bin/env python + +from Crypto.Cipher import AES +from Crypto import Random +import base64 +import os +import binascii +import json +import sys + +class JKaes: + + # the key size for the cipher object; must be 16, 24, or 32 for AES + KEY_SIZE = 16 + #always 16 bytes for aes + BLOCK_SIZE = 16 + + # the character used for padding--with a block cipher such as AES, the value + # you encrypt must be a multiple of BLOCK_SIZE in length. This character is + # used to ensure that your value is always a multiple of BLOCK_SIZE + #PADDING_CHARACTER = '{' + PADDING_CHARACTER = b'0' + PADDING = 0 + op = 'encode' + musicFile = '' + + KEY='' + IV='' + + CIPHER_MODE = AES.MODE_CBC + # CIPHER_MODE = AES.MODE_CFB + + def __init__(self, fileName, keyFile='',operation='encode'): + self.op = operation + self.musicFile = fileName + if len(keyFile) != 0: + self.initKeyFromFile(keyFile) + else: + if operation == 'encode': + self.generateNewKeys() + + # one-liner to sufficiently pad the text to be encrypted + def updatePadSize(self,dlen): + self.PADDING = (self.BLOCK_SIZE - dlen % self.BLOCK_SIZE) + + def getPadding(self): + return self.PADDING + + def pad(self,s): + self.updatePadSize(len(s)) + pdata = self.PADDING * self.PADDING_CHARACTER + if len(pdata) != self.PADDING : + sys.exit('Pad data length %d does match %d. Check python pad character size!' % + (len(pdata), self.PADDING)) + s = s + pdata + return s + + def EncodeAEStoB64(self,c, s): + return base64.b64encode(c.encrypt(self.pad(s))) + + def b64DecodeAES(self,c, e): + return c.decrypt(base64.b64decode(e)).rstrip(self.PADDING_CHARACTER) + + + def initKeyFromFile(self,fname): + (self.KEY,self.IV)= self.readAesKeyFile(fname) + + def generateNewKeys(self): + self.KEY = self.generateAesKey(); + self.IV = self.generateAesIv() + + def generateAesKey(self,keySize=KEY_SIZE): + # generate a random secret key + #secret = Random.get_random_bytes(keySize) + secret = Random.new().read(keySize) + return secret + + def generateAesIv(self): + secret = Random.new().read(AES.block_size) + return secret + + def getKeyStr(self): + str = '%s_%s_%s' % (len(self.KEY),base64.b64encode(self.IV),base64.b64encode(self.KEY)) + #print 'okey=',str + return str + def getKeyModeStr(self): + if self.CIPHER_MODE == AES.MODE_CBC: + return 'CBC' + elif self.CIPHER_MODE == AES.MODE_CFB: + return 'CFB' + else: + sys.exit('Bad AES key mode') + + def setKey(self, content): + (keySize, ivstr, keystr) = content.split('_') + #print 'ikey=',content + self.IV = base64.b64decode(ivstr) + self.KEY = base64.b64decode(keystr) + + def writeAesKeytoFile(self, iv,key,Keyfilename): + #initialization vector - iv + #key - must be the same size as the iv + #output filename + str = '%s_%s_%s' % (len(key),base64.b64encode(iv),base64.b64encode(key)) + #print 'okey=',str + fo = open(Keyfilename, 'w') + fo.write(str) + fo.close() + + def writeAesKeytoFile(self,Keyfilename): + self.writeAesKeytoFile(self.IV,self.KEY,Keyfilename) + + def readAesKeyFile(self,keyFilename): + # Given the filename of a file that contains a public or private key, + # return the key as a (n,e) or (n,d) tuple value. + fo = open(keyFilename) + content = fo.read() + fo.close() + (keySize, ivstr, keystr) = content.split('_') + + #print 'ikey=',content + iv = base64.b64decode(ivstr) + key = base64.b64decode(keystr) + return (int(keySize), iv, key) + + + def WriteFileData(self,outfile,data): + #ddata = base64.b64decode(data) + fi = open(outfile,'wb') + fi.write(data); + + def LoadFileData(self, infile): + fi = open(infile,'rb') + data = fi.read(); + return data + #edata = base64.b64encode(data) + #return edata + + + def WriteAesFileData(self, outfile,data): + # These files are assumed to be in cypher text - so we won't b64 encode/decode them + fo = open(outfile,'wb') + fo.write(data) + + def LoadAesFileData(self, infile): + # These files are assumed to be in cypher text - so we won't b64 encode/decode them + fi = open(infile,'rb') + data = fi.read(); + return data + + def EncodeFileToMsgWithKey(self, key, iv, infile): + infileData = self.LoadFileData(infile) + pdata = self.pad(infileData) + cipher = AES.new(key, self.CIPHER_MODE, iv) + msg = cipher.encrypt(pdata) + return msg + + + def EncodeFileWithKeyAndWrite(self, key, iv, infile,outFile): + msg = self.EncodeFileToMsgWithKey(key, iv, infile) + self.WriteAesFileData(outFile,msg) + return msg + + def EncodeFileToMsg(self, infile): + infileData = self.LoadFileData(infile) + # file data must be in plain text + pdata = self.pad(infileData) + cipher = AES.new(self.KEY, self.CIPHER_MODE, self.IV) + msg = cipher.encrypt(pdata) + return msg + + + def EncodeFileAndWrite(self, infile,outFile): + edata = self.EncodeFileToMsg(infile) + self.WriteAesFileData(outFile,edata) + #return edata + + def DecodeFileToMsgWithKey(self,key, iv, infile): + infileData = self.LoadAesFileData(infile) + cipher = AES.new(key, self.CIPHER_MODE, iv) + #expects the file to have the right number of blocks + data = cipher.decrypt(infileData) + return data + + def DecodeFileWithKeyAndWrite(self,key, iv, infile,outFile): + msg = self.DecodeFileToMsgWithKey(key, iv, infile) + self.WriteFileData(outFile,msg) + + def DecodeFileToMsg(self, infile): + msg = self.DecodeFileToMsgWithKey(self.KEY, self.IV, infile) + return msg + + def DecodeFileAndWrite(self, infile,outFile): + data = self.DecodeFileToMsg(infile) + self.WriteFileData(outFile,data) + #return data + + def DecodeMsg(self, pdata): + cipher = AES.new(self.KEY,self.CIPHER_MODE, self.IV) + data = cipher.decrypt(pdata) + return data + + def DecodeU64Msg(self, pdata): + cipher = AES.new(self.KEY, self.CIPHER_MODE, self.IV) + data = self.b64DecodeAES(cipher, pdata) + return data + + + + + + diff --git a/ruby/lib/py/jam_tracks/jkaes.pyc b/ruby/lib/py/jam_tracks/jkaes.pyc new file mode 100644 index 0000000000000000000000000000000000000000..ea98827c8205f5665c145f09a6d2e490d3e4f7e3 GIT binary patch literal 9156 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',tname + # write the content to tmp file + outTmpFile = tempfile.NamedTemporaryFile() + outTmpFile.write(fdata) + + track = JKtrack('dec_'+fname) + track.setKeyStr(aesKey) + track.DecodeBufferToFile(fdata,tname,padding) + if COMPARE_PARSEFILE: + # write the encrypted files out + fi = open('enc_'+tname,'wb') + fi.write(fdata); + fi.close() + + if filecmp.cmp(tname,fname): + print 'OK: file %s match %s' % (fname,tname) + else: + print 'BAD: file %s does not match %s' % (fname,tname) + + def parseContainer(self, rsaKeyFile): + # file must be zip file + zf = zipfile.ZipFile(self.packageFileInfo) + + #now decrypt data with rsa public key + rsa = JKrsa() + rsa.loadKey(rsaKeyFile) + + # get the jam package info file + pinfo = self.extractMediaMetaData(JAMTRACK_PACKAGE_INFO_FILE,rsa,zf) + fi = open(JAMTRACK_PACKAGE_INFO_FILE,'wb') + fi.write(pinfo); + fi.close() + + #get the media details + estr = self.extractMediaMetaData(JAMTRACK_MEDIA_META_FILE,rsa,zf) + data = json.loads(estr) + if DEBUG_ENABLE: + pprint(data) + + try: + coverFileInfoArray = data[JAMTRACK_COVER_ART_TAG] + try: + coverFileInfo= coverFileInfoArray[0] + cfile = coverFileInfo['datafile'] + aesKey = coverFileInfo['key'] + fname = coverFileInfo['filename'] + fsize = coverFileInfo['size'] + padding = coverFileInfo['padding'] + try: + fdata = zf.read(cfile) + except KeyError: + print 'ERROR: Did not find %s in zip file' % cfile + sys.exit() + else: + self.decryptAesFile(aesKey,fdata,fname,cfile,padding) + except: + print 'no cover art data' + except: + print 'no cover art' + + #now extract the file + mediaFilesInfo = data["tracks"] + + for mediaFileInfo in mediaFilesInfo: + aesKey = mediaFileInfo['key'] + fname = mediaFileInfo['filename'] + fsize = mediaFileInfo['size'] + tname = mediaFileInfo['trackname'] + padding = mediaFileInfo['padding'] + fdata = '' + try: + fdata = zf.read(tname) + except KeyError: + print 'ERROR: Did not find %s in zip file' % tname + sys.exit() + else: + self.decryptAesFile(aesKey,fdata,fname,tname,padding) + + diff --git a/ruby/lib/py/jam_tracks/jkasset.pyc b/ruby/lib/py/jam_tracks/jkasset.pyc new file mode 100644 index 0000000000000000000000000000000000000000..efd5ed263d50a59b13574b884d3cc839c725297c GIT binary patch literal 11420 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 YFM9uiZ@(}x0jx5j0wnWS6hXoN4;vafAOHXW literal 0 HcmV?d00001 diff --git a/ruby/lib/py/jam_tracks/jkcreate.py b/ruby/lib/py/jam_tracks/jkcreate.py new file mode 100755 index 000000000..e2272e17b --- /dev/null +++ b/ruby/lib/py/jam_tracks/jkcreate.py @@ -0,0 +1,249 @@ +import jkasset +import json +import jkasset +from pprint import pprint +import random +import sys, getopt +import jkmedia +import base64 +import tempfile +import argparse +from types import * +import unicodedata + +parser ='' +inputfiles = [] + +def help(): + parser.print_help() + + + +def media_arg(string): + #print 'media_arg:', string + try: + fname,ext = string.split('+') + #print fname + if fname == '': + print "### No music file in command line: ", string + raise argparse.ArgumentTypeError("Track file name empty") + + inputfiles.append(string) + except: + if string: + inputfiles.append(string) + pass + + return string + +def loadTracksFromList(fileName): + try: + lines = [line.strip() for line in open(fileName)] + #print lines + global inputfiles + inputfiles = lines + except: + print "Unable to open media filelist", fileName + help() + sys.exit(-1) + +def process(argv): + #print argv + global parser + parser = argparse.ArgumentParser( + prog='jkcreate', + description='JamTrack Packaging Tool', + epilog="Note: Meta file values may be update with title,sku,etc") + + parser.add_argument("-D", "--verbosity", + help="increase output verbosity", + action="store_true") + + parser.add_argument("-t", "--title", metavar='title', type=str, + help="Title of JamTrack. If not specified, the title in the metafile is used.") + + parser.add_argument("-k", "--sku", type=str, + help="The product SKU to use. If not specified, the SKU in the metafile is used.",required=True,) + + parser.add_argument("-c", "--cover", metavar='coverArtFile', type=str, + help="The cover art file. File should be JPEG or PNG.") + + parser.add_argument("-p", "--pkey", metavar='pkey.pem',type=str, + help="The output public key file. File should be .pem",required=True,) + + parser.add_argument("-s", "--skey", metavar='skey.pem', type=str, + help="The output private key file. File should be .pem",required=True,) + + + parser.add_argument("-m", "--meta",metavar='trackMetaFile', type=str, + help="The input JamTrack JSON metafile file. Optional") + + parser.add_argument("-o", "--ofile", metavar='JamTrackPage', type=str, + help="The output JamTrack file (.jkz)",required=True,) + + parser.add_argument("-I", "--infilesList", metavar='musicTrackFileList', type=str, + help=" -I 'file containing tracks'") + + parser.add_argument("-i", "--infiles", metavar='musictrack', type=media_arg, nargs='*', + help=" -i 'Lumme.ogg+Bass Guitar' -i 'Hydrate-Kenny_Beltrey.ogg+Bass Guitar'",) + + + #parser.print_help() + args = parser.parse_args(argv) + #print args + + try: + if args.verbosity: + jkasset.DEBUG_ENABLE = 1 + jkasset.COMPARE_PARSEFILE = True + #args.sku = random.randint(1, 100000000) + except: + pass + + + try: + if args.infilesList: + loadTracksFromList(args.infilesList) + except: + pass + #create json struct from info + metaJson={} + try: + if args.meta: + #try to load json data + try: + json_data=open(args.meta).read() + + metaJson = json.loads(json_data) + if jkasset.DEBUG_ENABLE : + pprint(metaJson) + except: + print 'Error processing json from file: ', args.meta + help() + sys.exit(-1) + except: + print 'No meta file specified' + pass + + jdata={} + mdata=[] + instdata={} + + if any(metaJson): + try: + #pickup the instrument data passed in - if any + instdata = metaJson["TrackInstrument"] + except: + pass + + i = 0 + trackLength = {} + trackLenStats=[] + + #print inputfiles + + if not any(inputfiles) : + print 'No track files specified ' + help() + sys.exit(-1) + + for mediaFileInfo in inputfiles: + #update track name and instrument name + #print mediaFileInfo + mediaFileInfo.strip(); + mlist = mediaFileInfo.split("+") + mediaFileInfo = mlist[0] + + trackName = 'track_%02d' % (i) + i = i + 1 + mdata.append({"name" : mediaFileInfo, "trackName": trackName}) + + try: + minfo = jkmedia.JKTrackInfo(mediaFileInfo) ; + tinfo={}; + tinfo['bitrate']=minfo.bitrate + tinfo['length'] = minfo.trackLength + trackLenStats.append(minfo.trackLength) + trackLength[trackName]= tinfo + except: + print("Cannot find file or read media information for '%s'"% mediaFileInfo) + #help() + sys.exit(-1) + + try: + instdata[trackName]=mlist[1] + except: + if instdata.has_key(trackName) == False: + print "No instrument for track ",trackName + pass + + try: + if args.title: + try: + title = base64.b64encode(args.title) + metaJson['Title']=title + except: + print 'Error processing title : ', title + help() + sys.exit(-1) + + if args.sku: + try: + metaJson['SKU']=args.sku + except: + print 'Error sku' + help() + sys.exit(-1) + + metaJson['METADATA_VER'] = 1 + + except: + #These are both optional.. + pass + + if any(instdata): + metaJson['TrackInstrument'] = instdata + if len (instdata) > len(mdata): + print "Number of instruments ", len (instdata)," in meta data greater than number of tracks ",len(mdata) + help() + sys.exit(-1) + + if any(trackLength): + metaJson['TrackData'] = trackLength + + #dump the meta data to temp file + + metaTmp = tempfile.NamedTemporaryFile(); + metaTmp.write(json.dumps(metaJson)) + metaTmp.seek(0) + + jdata["tracks"] = mdata + jdata["rsa_priv_file"]= args.skey + jdata["rsa_pub_file"]= args.pkey + jdata["container_file"]= args.ofile + + #jdata["jamktrack_info"]= trackMetaFile + jdata["jamktrack_info"]= metaTmp.name + + try: + jdata["coverart"]= args.cover + except: + print 'No cover art specified' + + data = json.dumps(jdata) + #pprint(data) + + fname = 'jt_metadata.json' + fo = open(fname, 'w') + fo.write(data) + fo.close() + + jas = jkasset.JKasset(fname) + + +if __name__ == "__main__": + random.seed() + process(sys.argv[1:]) + + + diff --git a/ruby/lib/py/jam_tracks/jkmedia.py b/ruby/lib/py/jam_tracks/jkmedia.py new file mode 100644 index 000000000..035abc3a4 --- /dev/null +++ b/ruby/lib/py/jam_tracks/jkmedia.py @@ -0,0 +1,44 @@ +#!/usr/bin/env python +import base64 +import os +import binascii +import json +import sys +from optparse import OptionParser +#from import mutagen.ogg +#from import mutagen.oggvorbis + +class JKTrackInfo: + trackLength =0 + bitrate = 0 + mediaFile=''; + + + def __init__(self, fileName): + #get the file extension + self.mediaFile = fileName + fileName, fileExtension = os.path.splitext(self.mediaFile) + audio = '' + if fileExtension == '.ogg' : + from mutagen.oggvorbis import OggVorbis + audio = OggVorbis(self.mediaFile) + elif fileExtension == '.wav' : + from mutagen.wavpack import WavPack + audio = WavPack(self.mediaFile) + elif fileExtension == '.mp3' : + from mutagen.mp3 import MP3 + audio = MP3(self.mediaFile) + elif fileExtension == '.flac' : + from mutagen.flac import FLAC + audio = FLAC(self.mediaFile) + else: + print "Unsupported filetype '",fileExtension, "' for file ", self.mediaFile + raise Exception("Unsupported filetype") + + print audio.info.length, audio.info.bitrate + self.bitrate = audio.info.bitrate + self.trackLength = audio.info.length + + + + diff --git a/ruby/lib/py/jam_tracks/jkrsa.py b/ruby/lib/py/jam_tracks/jkrsa.py new file mode 100755 index 000000000..4d0e38600 --- /dev/null +++ b/ruby/lib/py/jam_tracks/jkrsa.py @@ -0,0 +1,194 @@ +# RSA Cipher +# http://inventwithpython.com/hacking (BSD Licensed) + +from Crypto.Cipher import PKCS1_OAEP +from Crypto.PublicKey import RSA +from Crypto import Random +import base64 +import sys + +class JKrsa: + # IMPORTANT: The block size MUST be less than or equal to the key size! + # (Note: The block size is in bytes, the key size is in bits. There + # are 8 bits in 1 byte.) + #DEFAULT_BLOCK_SIZE = 128-2 # 128 bytes + DEFAULT_BLOCK_SIZE = 64 # 128 bytes + + + RSA_KEYSIZE = 1024 + BYTE_SIZE = 256 # One byte has 256 different values. + RSAKey=''; + PADDING = 0 + PADDING_CHARACTER =b'\0' + encipher=''; + decipher='' + + def __init__(self, operation='encode'): + self.op = operation + + def updatePadSize(self,dlen): + self.PADDING = (self.DEFAULT_BLOCK_SIZE - dlen % self.DEFAULT_BLOCK_SIZE) + + def getPadding(self): + return self.PADDING + + def pad(self,s): + self.updatePadSize(len(s)) + pdata = self.PADDING * self.PADDING_CHARACTER + if len(pdata) != self.PADDING : + sys.exit('Pad data length %d does match %d. Check python pad character size!', + (len(pdata), self.PADDING)) + s = s + pdata + return s + + def EncodeRSA(self,c, s): + #print 'len=',len(s) + estr = self.encipher.encrypt(s) + #print 'elen=',len(estr) + #print estr + return estr + + def DecodeRSA(self,c, e): + #print 'len=',len(e) + str = self.decipher.decrypt(e) + return str + + def generateKey(self, privateFileName='pri_Key.pem', publicFileName='pub_Key.pem'): + self.RSAKey = RSA.generate(self.RSA_KEYSIZE) + + public_key = self.RSAKey.publickey().exportKey("PEM") + private_key = self.RSAKey.exportKey("PEM") + + if privateFileName: + f = open(privateFileName,'w') + f.write(self.RSAKey.exportKey("PEM")) + f.close() + + f = open(privateFileName,'r') + skey = RSA.importKey(f.read()) + self.decipher = PKCS1_OAEP.new(skey) + f.close() + + if publicFileName: + f = open(publicFileName,'w') + f.write(self.RSAKey.publickey().exportKey("PEM")) + f.close() + + f = open(publicFileName,'r') + pkey = RSA.importKey(f.read()) + self.encipher = PKCS1_OAEP.new(pkey) + f.close() + + return private_key, public_key + + def loadKey(self, fileName='pri_Key.pem'): + f = open(fileName,'r') + self.RSAKey = RSA.importKey(f.read()) + self.decipher = PKCS1_OAEP.new(self.RSAKey) + f.close() + + def WriteFileData(self,outfile,data): + #ddata = base64.b64decode(data) + fi = open(outfile,'wb') + fi.write(data); + + def LoadFileData(self, infile): + fi = open(infile,'rb') + data = fi.read(); + #edata = base64.b64encode(data) + return data + + def WriteRSAFileData(self, outfile,data): + # These files are assumed to be in cypher text - so we won't b64 encode/decode them + fo = open(outfile,'wb') + #edata = base64.b64encode(data) + fo.write(data) + + + def LoadRSAFileData(self, infile): + # These files are assumed to be in cypher text - so we won't b64 encode/decode them + fi = open(infile,'rb') + data = fi.read(); + return data + + def getBlocksFromText(self,message, blockSize=DEFAULT_BLOCK_SIZE): + # Converts a string message to a list of block integers. Each integer + # represents 128 (or whatever blockSize is set to) string characters. + # messageBytes = message.encode('ascii') # convert the string to bytes + blockInts = [] + blockInts = [message[i:i+blockSize] for i in range(0, len(message), blockSize)] + return blockInts + + + def encryptMesssage(self, message, blockSize=DEFAULT_BLOCK_SIZE): + keySize = self.RSAKey.size() + 1; + + # Check that key size is greater than block size. + if keySize < blockSize * 8: # * 8 to convert bytes to bits + sys.exit('ERROR: Block size is %d bits and key size is %d bits.' + ' The RSA cipher requires the block size to be equal to' + ' or less than the key size. Either decrease the' + ' block size or use different keys.' % (blockSize * 8, keySize)) + + if len(message) % blockSize : # * 8 to convert bytes to bits + sys.exit('ERROR: Block size is %d and data size is %d .' + ' The RSA cipher requires the block size to be equal to' + ' or less than the key size. Either decrease the' + ' block size or use different keys.' % (blockSize, len(message))) + + + encryptedContent = [] + for block in self.getBlocksFromText(message, blockSize): + encryptedContent_ = self.EncodeRSA(self.RSAKey,block); + encryptedContent.extend(encryptedContent_) + + return encryptedContent + + def decryptMesssage(self, message): + #print message + #split in equal chunks + decryptedContent = [] + for block in self.getBlocksFromText(message, self.DEFAULT_BLOCK_SIZE*2): + decryptedContent_ = self.DecodeRSA(self.RSAKey,block); + decryptedContent.extend(decryptedContent_) + + return decryptedContent + + + def encryptAndWriteToFile(self, keyFilename, inFile,outFilename, blockSize=DEFAULT_BLOCK_SIZE): + # Using a key from a key file, encrypt the message and save it to a + # file. Returns the encrypted message string. + self.loadKey(keyFilename) + keySize = self.RSAKey.size()+1; + + # Check that key size is greater than block size. + if keySize < blockSize * 8: # * 8 to convert bytes to bits + sys.exit('ERROR: Block size is %s bits and key size is %s bits.' + ' The RSA cipher requires the block size to be equal to' + ' or less than the key size. Either decrease the' + ' block size or use different keys.' % (blockSize * 8, keySize)) + + # Encrypt the message + message = self.LoadFileData(inFile); + message = self.pad(message) + + encryptedContent = self.encryptMesssage(message); + self.WriteRSAFileData(outFilename,encryptedContent) + # Also return the encrypted string. + #return encryptedContent + + + def readFromFileAndDecrypt(self, keyFilename, inFile, outFilename): + # Using a key from a key file, read an encrypted message from a file + # and then decrypt it. Returns the decrypted message string. + self.loadKey(keyFilename) + + # Read in the message length and the encrypted message from the file. + message = self.LoadRSAFileData(inFile) + + decryptMessage = self.decryptMesssage(message) + self.WriteFileData(outFilename,decryptMessage) + + + + diff --git a/ruby/lib/py/jam_tracks/jktrack.py b/ruby/lib/py/jam_tracks/jktrack.py new file mode 100755 index 000000000..3e0dcd4b3 --- /dev/null +++ b/ruby/lib/py/jam_tracks/jktrack.py @@ -0,0 +1,104 @@ +import jkaes +import tempfile +from jkaes import JKaes +import os +class JKtrack: + mediaFile = '' + Name = '' + aesInKeyFile='' + aesCipher = '' + outTmpFile ='' + outPutFile = '' + def __init__(self, fileName, title='Unknown', inKeyFile=''): + self.mediaFile = fileName + self.Name = title + self.aesInKeyFile = inKeyFile + self.aesCipher = JKaes(self.mediaFile, self.aesInKeyFile) + + def getOutputFileName(self): + return self.outPutFile; + + def getKeyStr(self): + return self.aesCipher.getKeyStr(); + + def getEncryptPadding(self): + return self.aesCipher.getPadding() + + def setKeyStr(self,key): + self.aesCipher.setKey(key); + + def getKeyModeStr(self): + return self.aesCipher.getKeyModeStr() + + def getCoverEncryptFilePackageName(self,instance=-1): + #preserve the extentsion on the original name + fileName, fileExtension = os.path.splitext(self.mediaFile) + if instance != -1: + nm = "cover_%02d%s" % (instance,fileExtension) + return nm + else: + nm = os.path.basename(self.mediaFile) + return nm + + def getEncryptFilePackageName(self,instance=-1): + #preserve the extentsion on the original name + fileName, fileExtension = os.path.splitext(self.mediaFile) + if instance != -1: + nm = "track_%02d%s" % (instance,fileExtension) + return nm + else: + nm = os.path.basename(self.mediaFile) + return nm + + def Encode(self, outFile): + self.outPutFile = outFile + self.aesCipher.EncodeFileAndWrite( self.mediaFile, outFile) + + def EncodeToTmpFile(self): + self.outTmpFile = tempfile.NamedTemporaryFile() + self.Encode(self.outTmpFile.name) + + def EncodeWithKeyToFile(self,keyFile,outFile): + self.aesCipher.readAesKeyFile(keyFile) + self.Encode(outFile) + + def Decode(self, outFile): + self.outPutFile = outFile + self.aesCipher.DecodeFileAndWrite( self.mediaFile, outFile) + + def DecodeToTmpFile(self): + self.outTmpFile = tempfile.NamedTemporaryFile() + self.Decode(self.outTmpFile.name) + + def DecodeWithKeyToFile(self,keyFile,outFile): + self.aesCipher.readAesKeyFile(keyFile) + self.Decode(outFile) + + + def DecodeBufferToFile(self,msg,outfile,padding=0): + dmsg = self.aesCipher.DecodeMsg(msg) + fi = open(outfile,'wb') + fi.write(dmsg); + if padding > 0: + #trunckage the file by + fi.seek(-padding, os.SEEK_END) + fi.truncate() + fi.close() + return dmsg + + def DecodeU64Buffer(self,msg): + return self.aesCipher.DecodeU64Msg(msg) + + def setKey(self, keyFile): + self.aesCipher.readAesKeyFile(keyFile) + + def saveKey(self,keyFile): + self.aesCipher.writeAesKeytoFile(keyFile) + + def saveEncFileCopy(self,outfile): + fi = open(self.outPutFile,'rb') + fi.seek(0) + dmsg = fi.read(); + fo = open(outfile,'wb') + fo.write(dmsg); + return dmsg \ No newline at end of file diff --git a/ruby/lib/py/jam_tracks/jktrack.pyc b/ruby/lib/py/jam_tracks/jktrack.pyc new file mode 100644 index 0000000000000000000000000000000000000000..d065cbbe6aee5c45bc364f9d9dba2207c51113bd GIT binary patch literal 5712 zcmc&&>uwuG6h3P^cc)3yB)tJDl!6hoE)^6(xs^0XrD~`qsY*j7Yvb9Z>&x2OowN-~ zeJGux2C{o}8Dk4FTbI}78`cdu2hzUbmkbMv~PFnV{I+2sJ zK1tFzGbMIZfwI^!1*XMf|Ag#=!BYxPDm){0N;k}kEh}(Z?6d-NVoxb>M(m6N^I~Te zSP+YCb9%y}*fTnLR_we2=fo~3a9-@90vE)rR?dP|hbAhKheGsA>wH0qvyE~k%sg-2aMpJ=n-5o_= ztHnv|YBds{ksb*q^r_R-dQGKAW20mQCdq}|8YcmEw%vnmN2Ybf@Sq_Qej3MbMefIK z*Y#K_z&T821#}X;O8YdXJ?)KvzSZM^`wbaWq2o;GZq=nH!G)Ot+6A=#Ks03!q926T z#>v)6Q0;QrFDLbMr`yAP?f@GUX|Ji>%wwW2d$`|TpkeP-6)?_as)CB@g;oTg6lq2~ zL$oHkn@0=HU*v$;|D6@l&b$@f@7U<1EQwb17FtfY=88I*U`(L^RS!P_K#+t3Ah=N> zMXKUSL0;mA(1!#NNV6#EEv5m+$)ao)WbtK5c1yCFzluTc)qKIyorq;c5oZh~_0F>> ztzEf(!(PdJ&?GsXOk*FTmIj}!+lpQE!Wj*VRQE=hMG2f)-_bCl8{;HH#H&Y!x^fgU z!{+h}7bRKTNgNMP+C#JvN*8)vB3rrXGuk~s;tjVne!q0ih|5phb z=npEvEP_bGWNGNJDt2=o&_LYg0v9M|Lsu|wa20JxDTv4+*Vl{mLoB{tq||rct}kOS z$m)j;oZ-e-S-o&WQ!}(6ANH9wfE~_Cecn#&qZB5ok~t8Bm?4nkG{FHJk}w$mJT0FB z%19}*aX*`pYxU&!0C;!Y)6iP$`7>R!AdS+|7^}4f{mVt|E?viwZ)Q!qhM7(prdqPN zJejYxyX4i-sMTfFCz2N%3cJvS<2H?4E+2wGPpKh3TB} zSszM{*Y58`e`ELNQjcY2{@4pp8oVds_JGx6GkEh34mFqAy~~c_#9TplB6SiC+4I&n z{qt^<}WzB17Y z;rWIVRG9$&LDBD-xSwrlpzCy_L@(ISnFsQ#TGZ6csiny3^76gf^2!|@xO6+IhuFse zi)&XF>1Evq5c1o`v3c^)uuHh>t93owas$13Gah1mVX*gXez(238KpkFtY9{qMJK^r zFcVA%<-$Dr$w8>;$5`$*CA!>3UAcc;*P%x}K$y!F;jRpsw znbC=2?40pTM -s ' + + +def process(argv): + + global parser + parser = argparse.ArgumentParser( + prog='jkunpack', + description='JamTrack UnPackaging Tool', + epilog="Note: Files may be overwritten during unpacking") + + parser.add_argument("-D", "--verbosity", + help="increase output verbosity", + action="store_true") + + parser.add_argument("-s", "--skey", metavar='skey.pem', type=str, + help="The private key file. File should be .pem",required=True) + + parser.add_argument("-i", "--ifile", metavar='JamTrackPage', type=str, + help="The input JamTrack file (.jkz)",required=True) + + parser.print_help() + args = parser.parse_args(argv) + print args + + try: + if args.verbosity: + jkasset.DEBUG_ENABLE = 1 + jkasset.COMPARE_PARSEFILE = True + except: + pass + + + jas = jkasset.JKasset(args.ifile,'decode',args.skey) + +if __name__ == "__main__": + random.seed() + process(sys.argv[1:]) + + + diff --git a/ruby/lib/py/jam_tracks/jkzify.rb b/ruby/lib/py/jam_tracks/jkzify.rb new file mode 100755 index 000000000..c5ef594fd --- /dev/null +++ b/ruby/lib/py/jam_tracks/jkzify.rb @@ -0,0 +1,98 @@ +#!/usr/bin/env ruby +# +# Usage: jkzify [path to JamTrack WAVs] [destination for jkz and key files] +# +# Please review the comments, this script needs improvement -- I just threw it together to help me validate jkcreate.py +# + +wd = Dir.getwd +tracks_location = ARGV.shift +output_location = ARGV.shift +script_location = File.dirname(File.expand_path(__FILE__)) + + + +# first try to catch any issues with input arguments +def halt msg; warn msg; exit; end +halt "usage: jkzify path/to/wavs/ path/to/output" unless tracks_location && output_location +halt "path not found" unless File.exist?(tracks_location) && File.exist?(output_location) +# end + + + +# step 1: gather metadata from the track/folder names (and user input) +title = tracks_location.split('/').last.gsub(/'/,'') +puts "i think this track is called \"#{title}\"..." +shortname = title.gsub(/[aeiou\s]/,'').squeeze[0...8].downcase +puts "i'll call it #{shortname} for now" +puts "what sku do you want for this JamTrack? (press ENTER for '#{shortname}')" +input = STDIN.gets.chomp.strip +sku = input.empty? ? shortname : input + + + +# step 2: move WAVs to our own workspace +def renamed(t); t.gsub(/\s|'/,'_'); end #little helper + +Dir.chdir wd +`rm -rf #{shortname}` if File.exist? shortname +`mkdir #{shortname}` + +Dir.chdir tracks_location +Dir.glob('*.wav') do |track| + new_name = renamed track + `cp "#{track}" "#{wd}/#{shortname}/#{new_name}"` + puts "Copied from " + track + " to #{wd}/#{shortname}/" + new_name +end +Dir.chdir "#{wd}/#{shortname}" + + + +# step 3: generate OGGs from WAVs +oggs_location = title.downcase.gsub('\'','').split.join('_') + '_oggs/' +puts "generating OGGs in a separate folder #{oggs_location} (this may take some time)" +`mkdir #{oggs_location}` unless File.exist?(oggs_location) +Dir.glob('*.wav') do |track| + input = track + output = "#{oggs_location}#{File.basename(track, '.wav')}.ogg" + #puts "sox #{input} #{output}" + `sox #{input} #{output}` +end + + +# step 4: get all track parameters (names and instruments) +track_params = {} +track_files = [] +suffix = '\.wav' +Dir.foreach tracks_location do |track| + next if track =~ /Master Mix/i + next unless track =~ /#{suffix}$/i + print '.' + track.gsub!(/#{suffix}$/i, '') + instrument = track.split('-').drop(1).map(&:strip).join(' ') + parameter = "#{shortname}/#{oggs_location}#{renamed track}.ogg+#{instrument}" + #parameter.gsub!(/ /, '\ ') #spaces in filenames + track_params[instrument] = "-i '#{parameter}'" + track_files << parameter +end +puts "OK, #{track_params.length} tracks found" + + + +# step 5: create list of track titles +Dir.chdir wd +tracks_filename = "#{shortname}.txt" +File.open(tracks_filename, 'w+') { |f| f.puts track_files } + + + +# step 6: run jkcreate.py given all these parameters +public_key = "#{output_location}#{shortname}-pub.pem" +private_key = "#{output_location}#{shortname}-priv.pem" +output_jkz = "#{output_location}#{shortname}.jkz" +#puts "python jkcreate.py -D -k #{sku} -c art.png -p #{public_key} -s #{private_key} -I #{tracks_filename} -o #{output_jkz} -t '#{title}'" +`python jkcreate.py -D -k #{sku} -c art.png -p #{public_key} -s #{private_key} -I #{tracks_filename} -o #{output_jkz} -t '#{title}'` + + + +Dir.chdir wd \ No newline at end of file