VRFS-2481 : Jam Tracks python layer and source.

This commit is contained in:
Steven Miers 2014-12-14 19:42:38 -06:00
parent f6fef00ea5
commit ac2daed4da
18 changed files with 1461 additions and 1 deletions

1
ruby/bin/jamtrack.rb Normal file
View File

@ -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="}

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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="}

View File

@ -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

212
ruby/lib/py/jam_tracks/jkaes.py Executable file
View File

@ -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

Binary file not shown.

431
ruby/lib/py/jam_tracks/jkasset.py Executable file
View File

@ -0,0 +1,431 @@
import json
from jktrack import JKtrack
from jkrsa import JKrsa
from pprint import pprint
import sys
import os
import zipfile
import random
import base64
import tempfile
import datetime
import zipfile
import filecmp
#debug flags
DEBUG_ENABLE = 0
COMPARE_PARSEFILE = False
JAMTRACK_PACKAGE_VERSION = 1
JAMTRACK_PACKAGE_INFO_FILE = 'jamtrack.info'
JAMTRACK_MEDIA_META_FILE = 'media_meta.info'
JAMTRACK_COVER_ART_TAG ='cover_art'
def print_info(archive_name):
zf = zipfile.ZipFile(archive_name)
for info in zf.infolist():
print info.filename
print '\tComment:\t', info.comment
print '\tModified:\t', datetime.datetime(*info.date_time)
print '\tSystem:\t\t', info.create_system, '(0 = Windows, 3 = Unix)'
print '\tZIP version:\t', info.create_version
print '\tCompressed:\t', info.compress_size, 'bytes'
print '\tUncompressed:\t', info.file_size, 'bytes'
print
import zipfile
try:
import zlib
compression = zipfile.ZIP_DEFLATED
except:
compression = zipfile.ZIP_STORED
modes = { zipfile.ZIP_DEFLATED: 'deflated',
zipfile.ZIP_STORED: 'stored',
}
#use store - the encrypted files really does not gain from any zlib attempt to encrypt
compression = zipfile.ZIP_STORED
class JKasset:
rawMediaFiles=[]
encryptedMediaFiles = []
mediaAesKeyFile = []
packageFileInfo = ''
otherAssetFile = ''
coverArtFile=''
encryptedCoverFile =''
rsaPubKeyFile=''
rsaPrivKeyFile=''
outputPackageFile=''
packageFileName=''
def __init__(self, fileName, operation='encode', pubRsaKeyFile=''):
self.op = operation
self.packageFileInfo = fileName
if operation == 'encode':
self.loadEncodeContainerData()
self.generateContainer()
if operation == 'decode':
# print fileName
#self.loadDecodeContainerData()
self.parseContainer(pubRsaKeyFile)
def loadEncodeContainerData(self):
json_data=open(self.packageFileInfo)
jdata = json.load(json_data)
print
pprint(jdata)
json_data.close()
self.rawMediaFiles = jdata['tracks']
if len(self.rawMediaFiles) == 0:
sys.exit('ERROR: No tracks specified.')
try:
self.mediaAesKeyFile = jdata['aesKeyFiles']
except:
print "no aes key file "
self.otherAssetFile = jdata["jamktrack_info"]
if len(self.otherAssetFile) == 0:
sys.exit('ERROR: No JamTrack infoFile specified.')
self.rsaPrivKeyFile = jdata['rsa_priv_file']
self.rsaPubKeyFile = jdata["rsa_pub_file"]
if len(self.rsaPubKeyFile) == 0:
sys.exit('ERROR: A RSA pubkey file must be specified.')
self.outputPackageFile = jdata['container_file']
if len(self.outputPackageFile) == 0:
sys.exit('ERROR: A output container file must be specified.')
try:
self.coverArtFile = jdata['coverart']
except:
print 'no covert art file'
def encodeMediaFiles(self):
for mediaFileInfo in self.rawMediaFiles:
print 'mediaFileInfo:',mediaFileInfo
##the file, and track name
mediaFile = JKtrack(mediaFileInfo["name"],mediaFileInfo["trackName"])
if not self.mediaAesKeyFile :
mediaFile.EncodeToTmpFile();
else:
mediaFile.setKey(self.mediaAesKeyFile)
mediaFile.EncodeToTmpFile();
self.encryptedMediaFiles.append(mediaFile)
# Debug: save a copy of the encoded file
# mediaFile.saveEncFileCopy('enc_'+mediaFileInfo["name"])
def encodeCoverArt(self):
if not self.coverArtFile:
return
coverFile = JKtrack(self.coverArtFile,JAMTRACK_COVER_ART_TAG)
if not self.mediaAesKeyFile :
coverFile.EncodeToTmpFile();
else:
coverFile.setKey(self.mediaAesKeyFile)
coverFile.EncodeToTmpFile();
self.encryptedCoverFile = coverFile
def generateContainerCoverMetaData(self):
# create a json object with info on all the asset that are in the
# the container
if not self.encryptedCoverFile:
return '[{}]'
mediaInfo = []
trackNum=0
mediaFileInfo = self.encryptedCoverFile
if mediaFileInfo:
statinfo = os.stat(mediaFileInfo.getOutputFileName())
info = { 'filename': mediaFileInfo.getCoverEncryptFilePackageName(),
'datafile': mediaFileInfo.getCoverEncryptFilePackageName(trackNum),
'padding': mediaFileInfo.getEncryptPadding(),
'size': statinfo.st_size,
'keymode': mediaFileInfo.getKeyModeStr(),
'key': mediaFileInfo.getKeyStr()}
mediaInfo.append(info)
return mediaInfo;
def generateContainerMediaMetaData(self):
# create a json object with info on all the asset that are in the
# the container
mediaInfo = []
trackNum=0
for mediaFileInfo in self.encryptedMediaFiles:
statinfo = os.stat(mediaFileInfo.getOutputFileName())
info = { 'filename': mediaFileInfo.getEncryptFilePackageName(),
'trackname': mediaFileInfo.getEncryptFilePackageName(trackNum),
'padding': mediaFileInfo.getEncryptPadding(),
'size': statinfo.st_size,
'keymode': mediaFileInfo.getKeyModeStr(),
'key': mediaFileInfo.getKeyStr()}
trackNum += 1
mediaInfo.append(info)
return mediaInfo;
def addJamTrackAssetToContainer(self,assetfile,rsa,zfile):
#this is assumed to be text file..
fi = open(assetfile,'rb')
fi.seek(0)
amsg = fi.read();
pstr = rsa.pad(amsg)
#print pstr
if DEBUG_ENABLE != 0:
print 'plaintext:', pstr
encMediaStr = rsa.encryptMesssage(pstr)
edata = ''.join(encMediaStr)
metaInfoFile = tempfile.NamedTemporaryFile()
metaInfoFile.write(edata)
metaInfoFile.seek(0)
if DEBUG_ENABLE != 0:
ddata = rsa.decryptMesssage(bytes(edata))
print 'decrypt: ', ''.join(ddata)
try:
zfile.write(metaInfoFile.name,
arcname=JAMTRACK_PACKAGE_INFO_FILE, compress_type=compression)
except:
sys.exit("error writing package info file")
def initContainer(self):
mediaMeta = {'JPACK_VER': JAMTRACK_PACKAGE_VERSION,
'jamktrack_info' : self.otherAssetFile,
JAMTRACK_COVER_ART_TAG : self.generateContainerCoverMetaData(),
"tracks": self.generateContainerMediaMetaData()}
mediaMeta_str = json.dumps( mediaMeta )
if DEBUG_ENABLE != 0:
pprint(mediaMeta)
#print mediaMeta_str
#now rsa encrypt this string
rsa = JKrsa()
rsa.generateKey(self.rsaPrivKeyFile, self.rsaPubKeyFile)
mediaMeta_str = rsa.pad(mediaMeta_str)
if DEBUG_ENABLE != 0:
print 'plaintext:', mediaMeta_str
encMediaStr = rsa.encryptMesssage(mediaMeta_str)
edata = ''.join(encMediaStr)
#write the encrypted media info to a file so we can zip in the asset
metaInfoFile = tempfile.NamedTemporaryFile()
metaInfoFile.write(edata)
metaInfoFile.seek(0)
#try decrypting the data
if DEBUG_ENABLE != 0:
ddata = rsa.decryptMesssage(bytes(edata))
print 'decrypt: ', ''.join(ddata)
#zip package
if DEBUG_ENABLE != 0:
print 'creating archive'
#self.packageFileName = outfile = "media_%s" % (self.outputPackageFile)
self.packageFileName = outfile = "%s" % (self.outputPackageFile)
zfile = zipfile.ZipFile(outfile, mode='w')
try:
if DEBUG_ENABLE != 0:
print 'adding media_meta file with compression mode', modes[compression]
zfile.write(metaInfoFile.name,
arcname=JAMTRACK_MEDIA_META_FILE, compress_type=compression)
except:
sys.exit("error writing media info file")
#also add the other asset file - contain jamtrack title and other description etc...
self.addJamTrackAssetToContainer(self.otherAssetFile,rsa,zfile)
zfile.close()
#print_info(outfile)
def generateContainer(self):
self.encodeMediaFiles()
self.encodeCoverArt();
self.initContainer()
#now append file to container
zf = zipfile.ZipFile(self.packageFileName, mode='a')
if self.encryptedCoverFile:
try:
zf.write(self.encryptedCoverFile.getOutputFileName(),
arcname=self.encryptedCoverFile.getCoverEncryptFilePackageName(0),
compress_type=compression)
except:
sys.exit("error writing cover art info container file")
trackNum=0
for mediaFileInfo in self.encryptedMediaFiles:
# store the file in the archive under the track name
try:
zf.write(mediaFileInfo.getOutputFileName(),
arcname=mediaFileInfo.getEncryptFilePackageName(trackNum),
compress_type=compression)
except:
sys.exit("error writing media info container file")
trackNum = trackNum + 1
zf.close()
#dump the details of the final package
if DEBUG_ENABLE != 0:
print_info(self.packageFileName)
def extractMediaMetaData(self,fname,rsa,zf):
# first extract the media_meta file
metadata =''
for info in zf.infolist():
if fname in info.filename:
try:
metadata = zf.read(info.filename)
except KeyError:
print 'ERROR: Did not find %s in zip file' % info.filename
sys.exit()
break
if metadata == '':
print 'No media meta data found in package'
sys.exit()
metadata = rsa.decryptMesssage(bytes(metadata))
#print metadata
#convert to to string
estr = ''.join(metadata)
#strip padding
estr = estr.rstrip(b'\0')
if DEBUG_ENABLE:
print estr
return estr
def extractCoverArtData(self,fname,zf):
# first extract the media_meta file
metadata =''
for info in zf.infolist():
if fname in info.filename:
try:
metadata = zf.read(info.filename)
except KeyError:
print 'ERROR: Did not find %s in zip file' % info.filename
sys.exit()
break
if metadata == '':
print 'No cover art data found in package'
sys.exit()
metadata = rsa.decryptMesssage(bytes(metadata))
#print metadata
#convert to to string
estr = ''.join(metadata)
#strip padding
estr = estr.rstrip(b'\0')
if DEBUG_ENABLE:
print estr
return estr
def decryptAesFile(self,aesKey,fdata,fname,tname, padding):
print fname,'->',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)

Binary file not shown.

View File

@ -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:])

View File

@ -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

194
ruby/lib/py/jam_tracks/jkrsa.py Executable file
View File

@ -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)

104
ruby/lib/py/jam_tracks/jktrack.py Executable file
View File

@ -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

Binary file not shown.

View File

@ -0,0 +1,56 @@
import jkasset
import json
import jkasset
from pprint import pprint
import random
import sys, getopt
import base64
import tempfile
import argparse
from types import *
import unicodedata
parser =''
def help():
parser.print_help()
#print sys.argv[0],'[-D] -d -i <jamtrack.jkz> -s <privatekeyfile>'
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:])

View File

@ -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