├── .gitignore ├── README.md ├── catalog.py ├── config.example.json ├── consumerKey.py └── nugget.py /.gitignore: -------------------------------------------------------------------------------- 1 | config.json -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Operation-Chicken-Nugget 2 | 3 | Goal of this Operation is, grabbing a KS1 in Roubaix.
4 | **Don't run this on a VPS, you will get flagged for Fraud** 5 | 6 | **Dependencies**
7 | 8 | ``` 9 | pip3 install requests ovh 10 | ``` 11 | 12 | 1. Create an Application
13 | https://ca.api.ovh.com/createApp/
14 | https://eu.api.ovh.com/createApp/
15 | 16 | 2. Put the keys into config.json
17 | Example how config.json should look like by now
18 | 19 | ``` 20 | { 21 | "endpoint":"ovh-ca", 22 | "endpointAPI":"ca.api.ovh.com", 23 | "ovhSubsidiary":"CA", 24 | "application_key":"xxxxxxxxxx", 25 | "application_secret":"xxxxxxxxxxxxxxxxxx", 26 | "dedicated_datacenter":"fr", 27 | "region":"europe", 28 | "consumer_key":"" 29 | } 30 | ``` 31 | 32 | 2. Request the consumerKey with running consumerKey.py and put it into config.json
33 | 34 | 3. Edit nugget.py if you want to, by default it does no autopay and only in RBX
35 | If you want GRA, uncomment a few lines.
36 | 37 | 4. Profit!
38 | -------------------------------------------------------------------------------- /catalog.py: -------------------------------------------------------------------------------- 1 | import requests 2 | 3 | endpoint = "ca.api.ovh.com" 4 | response = requests.get(f'https://{endpoint}/1.0/order/catalog/public/eco?ovhSubsidiary=WE') 5 | catalog = response.json() 6 | catalogSorted = {} 7 | for plan in catalog['plans']: 8 | for price in plan['pricings']: 9 | if "installation" in price['capacities']: continue 10 | if price['interval'] != 1: continue 11 | catalogSorted[price['price']] = plan 12 | 13 | newlist = dict(sorted(catalogSorted.items(), key=lambda item: item[0])) 14 | 15 | for price,offer in newlist.items(): 16 | if "product" in offer: 17 | print(price,offer["invoiceName"]) 18 | for addon in offer['addonFamilies']: 19 | if addon['mandatory'] != True: continue 20 | print(addon) 21 | -------------------------------------------------------------------------------- /config.example.json: -------------------------------------------------------------------------------- 1 | { 2 | "endpoint":"", 3 | "ovhSubsidiary":"", 4 | "application_key":"", 5 | "application_secret":"", 6 | "dedicated_datacenter":"", 7 | "region":"", 8 | "consumer_key":"" 9 | } -------------------------------------------------------------------------------- /consumerKey.py: -------------------------------------------------------------------------------- 1 | import json, ovh 2 | 3 | with open('config.json') as f: 4 | config = json.load(f) 5 | 6 | # create a client using configuration 7 | client = ovh.Client( 8 | endpoint=config['endpoint'], 9 | application_key=config['application_key'], 10 | application_secret=config['application_secret'] 11 | ) 12 | 13 | # Request RO, /me API access 14 | ck = client.new_consumer_key_request() 15 | ck.add_recursive_rules(ovh.API_READ_WRITE, "/") 16 | 17 | # Request token 18 | validation = ck.request() 19 | 20 | print("Please visit %s to authenticate" % validation['validationUrl']) 21 | input("and press Enter to continue...") 22 | 23 | # Print nice welcome message 24 | print("Welcome", client.get('/me')['firstname']) 25 | print("Btw, your 'consumerKey' is '%s'" % validation['consumerKey']) -------------------------------------------------------------------------------- /nugget.py: -------------------------------------------------------------------------------- 1 | import requests, hashlib, json, time, ovh 2 | from datetime import datetime 3 | from random import randint 4 | 5 | with open('config.json') as f: 6 | config = json.load(f) 7 | 8 | # Instantiate. Visit https://api.ovh.com/createToken/?GET=/me 9 | # to get your credentials 10 | client = ovh.Client( 11 | endpoint=config['endpoint'], 12 | application_key=config['application_key'], 13 | application_secret=config['application_secret'], 14 | consumer_key=config['consumer_key'], 15 | ) 16 | 17 | # Print nice welcome message 18 | print("Welcome", client.get('/me')['firstname']) 19 | 20 | headers = {'Accept': 'application/json','X-Ovh-Application':config['application_key'],'X-Ovh-Consumer':config['consumer_key'], 21 | 'Content-Type':'application/json;charset=utf-8','Host':config['endpointAPI']} 22 | print("Preparing Package") 23 | #getting current time 24 | response = requests.get(f"https://{config['endpointAPI']}/1.0/auth/time", headers=headers) 25 | if response.status_code == 200: 26 | print("Getting Time") 27 | else: 28 | print(response.status_code) 29 | print(json.dumps(response.json(), indent=4)) 30 | exit() 31 | timeDelta = int(response.text) - int(time.time()) 32 | #run for 8 days 33 | for day in range(4): 34 | print(f'Day {day}') 35 | # creating a new cart 36 | cart = client.post("/order/cart", ovhSubsidiary=config['ovhSubsidiary'], _need_auth=False) 37 | #assign new cart to current user 38 | client.post("/order/cart/{0}/assign".format(cart.get("cartId"))) 39 | #put ks1 into cart 40 | #result = client.post(f'/order/cart/{cart.get("cartId")}/eco',{"duration":"P1M","planCode":"22sk010","pricingMode":"default","quantity":1}) 41 | #apparently this shit sends malformed json whatever baguette 42 | payload={'duration':'P1M','planCode':'22sk010','pricingMode':'default','quantity':1} 43 | response = requests.post(f"https://{config['endpointAPI']}/1.0/order/cart/{cart.get('cartId')}/eco", headers=headers, data=json.dumps(payload)) 44 | if response.status_code != 200: 45 | print(response.status_code) 46 | print(json.dumps(response.json(), indent=4)) 47 | exit() 48 | #getting current cart 49 | response = requests.get(f"https://{config['endpointAPI']}/1.0/order/cart/{cart.get('cartId')}") 50 | if response.status_code != 200: 51 | print(response.status_code) 52 | print(json.dumps(response.json(), indent=4)) 53 | exit() 54 | #modify item for checkout 55 | itemID = response.json()['items'][0] 56 | print(f'Getting current cart {cart.get("cartId")}') 57 | #set configurations 58 | configurations = [{'label':'region','value':config['region']},{'label':'dedicated_datacenter','value':config['dedicated_datacenter']},{'label':'dedicated_os','value':'none_64.en'}] 59 | for entry in configurations: 60 | response = requests.post(f"https://{config['endpointAPI']}/1.0/order/cart/{cart.get('cartId')}/item/{itemID}/configuration", headers=headers, data=json.dumps(entry)) 61 | if response.status_code == 200: 62 | print(f"Setting {entry}") 63 | else: 64 | print(response.status_code) 65 | print(json.dumps(response.json(), indent=4)) 66 | exit() 67 | #set options 68 | options = [{'itemId':itemID,'duration':'P1M','planCode':'bandwidth-100-included-ks','pricingMode':'default','quantity':1}, 69 | {'itemId':itemID,'duration':'P1M','planCode':'noraid-1x1000sa-sk010','pricingMode':'default','quantity':1}, 70 | {'itemId':itemID,'duration':'P1M','planCode':'ram-4g-sk010','pricingMode':'default','quantity':1} 71 | ] 72 | for option in options: 73 | response = requests.post(f"https://{config['endpointAPI']}/1.0/order/cart/{cart.get('cartId')}/eco/options", headers=headers, data=json.dumps(option)) 74 | if response.status_code == 200: 75 | print(f"Setting {option}") 76 | else: 77 | print(response.status_code) 78 | print(json.dumps(response.json(), indent=4)) 79 | exit() 80 | print("Package ready, waiting for stock") 81 | #the order expires in about 3 days, we create a new one after 2 days 82 | for check in range(17280): 83 | now = datetime.now() 84 | print(f'Run {check+1} {now.strftime("%H:%M:%S")}') 85 | #wait for stock 86 | response = requests.get('https://us.ovh.com/engine/apiv6/dedicated/server/datacenter/availabilities?excludeDatacenters=false&planCode=22sk010&server=22sk010') 87 | if response.status_code == 200: 88 | stock = response.json() 89 | score = 0 90 | for datacenter in stock[0]['datacenters']: 91 | #if datacenter['availability'] != "unavailable": score = score +1 92 | if datacenter['datacenter'] == "rbx": 93 | print(f'RBX {datacenter["availability"]}') 94 | if datacenter['availability'] != "unavailable": score = score +1 95 | if datacenter['datacenter'] == "gra": 96 | print(f'GRA {datacenter["availability"]}') 97 | if datacenter['availability'] == "unavailable": score = score +1 98 | else: 99 | time.sleep(randint(5,10)) 100 | continue 101 | #lets checkout boooyaaa 102 | #if score >= 1: 103 | if score == 2: 104 | #autopay should be set to true if you want automatic delivery, otherwise it will just generate a invoice 105 | payload={'autoPayWithPreferredPaymentMethod':False,'waiveRetractationPeriod':False} 106 | #prepare sig 107 | target = f"https://{config['endpointAPI']}/1.0/order/cart/{cart.get('cartId')}/checkout" 108 | now = str(int(time.time()) + timeDelta) 109 | signature = hashlib.sha1() 110 | signature.update("+".join([config['application_secret'], config['consumer_key'],'POST', target, json.dumps(payload), now]).encode('utf-8')) 111 | headers['X-Ovh-Signature'] = "$1$" + signature.hexdigest() 112 | headers['X-Ovh-Timestamp'] = now 113 | response = requests.post(target, headers=headers, data=json.dumps(payload)) 114 | if response.status_code == 200: 115 | print(response.status_code) 116 | print(json.dumps(response.json(), indent=4)) 117 | exit("Done") 118 | else: 119 | print("Got non 200 response code on checkout, retrying") 120 | continue 121 | time.sleep(10) --------------------------------------------------------------------------------