blob: 8c2949234875fd73dbf8022f0feecce54ef016fe [file] [log] [blame]
Mike Frysinger63bb3c72019-09-01 15:16:26 -04001#!/usr/bin/env python2
Jon Salzf10ef792014-04-01 14:25:36 +08002#
Hung-Te Lin1990b742017-08-09 17:34:57 +08003# Copyright 2014 The Chromium OS Authors. All rights reserved.
Jon Salzf10ef792014-04-01 14:25:36 +08004# Use of this source code is governed by a BSD-style license that can be
5# found in the LICENSE file.
6
7
8"""A command-line tool for reg code handling."""
9
Yilin Yang71e39412019-09-24 09:26:46 +080010from __future__ import print_function
Jon Salzf10ef792014-04-01 14:25:36 +080011
Jon Salz34008632014-07-08 16:27:40 +080012import base64
Jon Salz1c954152014-04-08 11:48:39 +080013import binascii
Jon Salz2fc97202014-04-21 16:42:59 +080014import logging
Jon Salz1c954152014-04-08 11:48:39 +080015import random
16import sys
17
Yilin Yang8cc5dfb2019-10-22 15:58:53 +080018from six.moves import input
19
Peter Shih67c7c0f2018-02-26 11:23:59 +080020import factory_common # pylint: disable=unused-import
Hung-Te Linb6287242016-05-18 14:39:05 +080021from cros.factory.device import device_utils
Yong Hongf6f959e2017-12-26 16:37:49 +080022from cros.factory.hwid.v3 import hwid_utils
Jon Salz1c954152014-04-08 11:48:39 +080023from cros.factory.proto import reg_code_pb2
Hung-Te Lin3f096842016-01-13 17:37:06 +080024from cros.factory.test.rules import registration_codes
25from cros.factory.test.rules.registration_codes import RegistrationCode
Hung-Te Lin03bf7ab2016-06-16 17:26:19 +080026from cros.factory.utils.argparse_utils import CmdArg
27from cros.factory.utils.argparse_utils import Command
28from cros.factory.utils.argparse_utils import ParseCmdline
Peter Shih33fbef72017-08-17 16:14:11 +080029from cros.factory.utils.cros_board_utils import BuildBoard
Hung-Te Lin4e6357c2016-01-08 14:32:00 +080030from cros.factory.utils import sys_utils
Jon Salzf10ef792014-04-01 14:25:36 +080031
32
33@Command('decode',
34 CmdArg('regcode', metavar='REGCODE',
35 help='Encoded registration code string'))
36def Decode(options):
37 reg_code = RegistrationCode(options.regcode)
38 if reg_code.proto:
Yilin Yang71e39412019-09-24 09:26:46 +080039 print(reg_code.proto)
Jon Salzf10ef792014-04-01 14:25:36 +080040 else:
Yilin Yang71e39412019-09-24 09:26:46 +080041 print(reg_code)
Jon Salzf10ef792014-04-01 14:25:36 +080042
43
Jon Salz1c954152014-04-08 11:48:39 +080044@Command(
Hung-Te Lin56b18402015-01-16 14:52:30 +080045 'generate-dummy',
Yong Hong503a2b82017-07-26 18:25:52 +080046 CmdArg('--project', '-p', metavar='PROJECT', required=True,
47 help=('Project to generate codes for. This must be exactly the '
48 'same as the HWID project name, except lowercase.')),
Hung-Te Lin56b18402015-01-16 14:52:30 +080049 CmdArg('--type', '-t', metavar='TYPE', required=True,
50 choices=['unique', 'group'],
51 help='The type of code to generate (choices: %(choices)s)'),
52 CmdArg('--seed', '-s', metavar='INT', type=int, default=None,
53 help='Seed to use for pseudo-random payload; defaults to clock'))
Jon Salz1c954152014-04-08 11:48:39 +080054def GenerateDummy(options):
Yilin Yang44d7f442020-01-06 12:11:42 +080055 print('*** This may be used only to generate a code for testing, '
56 'not for a real device.')
Yilin Yang8cc5dfb2019-10-22 15:58:53 +080057 yes_no = input('*** Are you OK with that? (yes/no) ')
Jon Salz1c954152014-04-08 11:48:39 +080058 if yes_no != 'yes':
Yilin Yang71e39412019-09-24 09:26:46 +080059 print('Aborting.')
Jon Salz1c954152014-04-08 11:48:39 +080060 sys.exit(1)
61
62 random.seed(options.seed)
63 proto = reg_code_pb2.RegCode()
64 proto.content.code_type = (reg_code_pb2.UNIQUE_CODE
65 if options.type == 'unique'
66 else reg_code_pb2.GROUP_CODE)
67
68 # Use this weird magic string for the first 16 characters to make it
69 # obvious that this is a dummy code. (Base64-encoding this string
70 # results in a reg code that looks like
Jon Salz34008632014-07-08 16:27:40 +080071 # '=CiwKIP______TESTING_______'...)
Jon Salz1c954152014-04-08 11:48:39 +080072 proto.content.code = (
Hung-Te Lin56b18402015-01-16 14:52:30 +080073 '\xff\xff\xff\xff\xffLD\x93 \xd1\xbf\xff\xff\xff\xff\xff' + ''.join(
74 chr(random.getrandbits(8))
Yong Hong503a2b82017-07-26 18:25:52 +080075 for i in range(
76 registration_codes.REGISTRATION_CODE_PAYLOAD_BYTES - 16)))
77 proto.content.device = options.project.lower()
Jon Salz1c954152014-04-08 11:48:39 +080078 proto.checksum = (
Hung-Te Lin56b18402015-01-16 14:52:30 +080079 binascii.crc32(proto.content.SerializeToString()) & 0xFFFFFFFF)
Jon Salz1c954152014-04-08 11:48:39 +080080
Jon Salz34008632014-07-08 16:27:40 +080081 encoded_string = '=' + base64.urlsafe_b64encode(
82 proto.SerializeToString()).strip()
Jon Salz1c954152014-04-08 11:48:39 +080083
84 # Make sure the string can be parsed as a sanity check (this will catch,
85 # e.g., invalid device names)
86 reg_code = RegistrationCode(encoded_string)
Yilin Yang71e39412019-09-24 09:26:46 +080087 print('')
88 print(reg_code.proto)
89 print(encoded_string)
Jon Salz1c954152014-04-08 11:48:39 +080090
91
Jon Salz2fc97202014-04-21 16:42:59 +080092@Command(
Hung-Te Lin56b18402015-01-16 14:52:30 +080093 'check',
94 CmdArg(
95 '--unique-code', '-u', metavar='UNIQUE_CODE',
Yong Hong503a2b82017-07-26 18:25:52 +080096 help=('Unique/user code to check (default: ubind_attribute RW VPD '
97 'value)')),
Hung-Te Lin56b18402015-01-16 14:52:30 +080098 CmdArg(
99 '--group-code', '-g', metavar='GROUP_CODE',
100 help='Group code to check (default: gbind_attribute RW VPD value)'),
101 CmdArg(
Yong Hong503a2b82017-07-26 18:25:52 +0800102 '--project', '-b', metavar='PROJECT',
103 help=('Project to check (default: probed project name if run on DUT; '
Wei-Han Chenfddc8842019-01-07 23:19:29 +0800104 'board name in .default_board if in chroot)')),
105 CmdArg(
106 '--allow_dummy', action='store_true',
107 help='Allow dummy regcode (regcode containing "__TESTING__")'))
Jon Salz2fc97202014-04-21 16:42:59 +0800108def Check(options):
Yong Hong503a2b82017-07-26 18:25:52 +0800109 if not options.project:
110 if sys_utils.InChroot():
111 options.project = BuildBoard().short_name
112 else:
Yong Hongf6f959e2017-12-26 16:37:49 +0800113 options.project = hwid_utils.ProbeProject()
Yong Hong503a2b82017-07-26 18:25:52 +0800114 logging.info('Device name: %s', options.project)
Jon Salz2fc97202014-04-21 16:42:59 +0800115
116 rw_vpd = None
117 success = True
Hung-Te Linb6287242016-05-18 14:39:05 +0800118 dut = device_utils.CreateDUTInterface()
Jon Salz2fc97202014-04-21 16:42:59 +0800119
120 for code_type, vpd_attribute, code in (
121 (RegistrationCode.Type.UNIQUE_CODE,
122 'ubind_attribute', options.unique_code),
123 (RegistrationCode.Type.GROUP_CODE,
124 'gbind_attribute', options.group_code)):
125
126 if not code:
127 if rw_vpd is None:
Hung-Te Linf5f2d7f2016-01-08 17:12:46 +0800128 if sys_utils.InChroot():
Jon Salz2fc97202014-04-21 16:42:59 +0800129 sys.stderr.write('error: cannot read VPD from chroot; use -u/-g\n')
130 sys.exit(1)
131
Hung-Te Lincf12e8e2015-11-24 14:13:19 +0800132 rw_vpd = dut.vpd.rw.GetAll()
Guohui Zhouf9687752019-05-24 16:00:52 +0800133 code = rw_vpd.get(vpd_attribute)
Jon Salz2fc97202014-04-21 16:42:59 +0800134 if not code:
135 sys.stderr.write('error: %s is not present in RW VPD\n' %
136 vpd_attribute)
137 sys.exit(1)
138
139 try:
Wei-Han Chenfddc8842019-01-07 23:19:29 +0800140 registration_codes.CheckRegistrationCode(code, code_type, options.project,
141 options.allow_dummy)
Jon Salz2fc97202014-04-21 16:42:59 +0800142 logging.info('%s: success', code_type)
143 except registration_codes.RegistrationCodeException as e:
144 success = False
145 logging.error('%s: failed: %s', code_type, str(e))
146
147 sys.exit(0 if success else 1)
148
149
Jon Salzf10ef792014-04-01 14:25:36 +0800150def main():
Jon Salz2fc97202014-04-21 16:42:59 +0800151 logging.basicConfig(level=logging.INFO)
Jon Salzf10ef792014-04-01 14:25:36 +0800152 options = ParseCmdline('Registration code tool.')
153 options.command(options)
154
155
156if __name__ == '__main__':
157 main()