Skip to content

Commit

Permalink
Merge pull request openedx#491 from jauzzz/ironwood
Browse files Browse the repository at this point in the history
user profile mobile field change
  • Loading branch information
xavierchan authored Dec 13, 2019
2 parents fbb421e + 7f5bd20 commit 0fd0555
Show file tree
Hide file tree
Showing 7 changed files with 129 additions and 2 deletions.
34 changes: 34 additions & 0 deletions common/djangoapps/student/fields.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
from django.db.models import CharField


class HashCharField(CharField):
description = "A hashed field"

def __init__(self, verbose_name=None, name=None, hasher=None, *args, **kwargs):
self.hasher = hasher
super(HashCharField, self).__init__(*args, **kwargs)

def deconstruct(self):
name, path, args, kwargs = super(HashCharField, self).deconstruct()
if self.hasher:
kwargs['hasher'] = self.hasher
return name, path, args, kwargs

def from_db_value(self, value, expression, connection, context):
if value is None:
return value
return self.hasher.decrypt(value)

def get_prep_value(self, value):
if value is None:
return value
return self.hasher.encrypt(value)

def get_prep_lookup(self, lookup_type, value):
# TODO: maybe more lookup type, need to check
if lookup_type == 'exact':
return self.get_prep_value(value)
elif lookup_type == 'in':
return [self.get_prep_value(v) for v in value]
else:
raise TypeError('Lookup type %r not supported.' % lookup_type)
39 changes: 39 additions & 0 deletions common/djangoapps/student/hasher.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
import base64
import hashlib
from Crypto import Random
from Crypto.Cipher import AES
from django.conf import settings


class AESCipher(object):

@classmethod
def encrypt(cls, raw):
if raw is None:
return raw
key = hashlib.sha256(settings.AES_KEY).digest()
raw = cls._pad(raw)
# iv = Random.new().read(AES.block_size)
# use settings iv instead of random to produce same result
iv = settings.AES_IV
cipher = AES.new(key, AES.MODE_CBC, iv)
return base64.b64encode(iv + cipher.encrypt(raw.encode()))

@classmethod
def decrypt(cls, enc):
if enc is None:
return enc
key = hashlib.sha256(settings.AES_KEY).digest()
enc = base64.b64decode(enc)
iv = enc[:AES.block_size]
cipher = AES.new(key, AES.MODE_CBC, iv)
return cls._unpad(cipher.decrypt(enc[AES.block_size:])).decode('utf-8')

@classmethod
def _pad(cls, s):
bs = AES.block_size
return s + (bs - len(s) % bs) * chr(bs - len(s) % bs)

@classmethod
def _unpad(cls, s):
return s[:-ord(s[len(s) - 1:])]
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
# -*- coding: utf-8 -*-
# Generated by Django 1.11.20 on 2019-05-10 06:17
from __future__ import unicode_literals

from django.db import migrations
from student.models import UserProfile
from student.hasher import AESCipher

def forwards_func(apps, schema_editor):
users = UserProfile.objects.all()
hasher = AESCipher
for profile in users:
profile.phone = hasher.encrypt(profile.phone)
profile.save(update_fields=['phone'])


class Migration(migrations.Migration):

dependencies = [
('student', '0020_merge_20190510_0217'),
]

operations = [
migrations.RunPython(forwards_func),
]
22 changes: 22 additions & 0 deletions common/djangoapps/student/migrations/0022_auto_20191213_0427.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
# -*- coding: utf-8 -*-
# Generated by Django 1.11.20 on 2019-12-13 09:27
from __future__ import unicode_literals

from django.db import migrations
import student.fields
import student.hasher


class Migration(migrations.Migration):

dependencies = [
('student', '0021_hash_userprofile'),
]

operations = [
migrations.AlterField(
model_name='userprofile',
name='phone',
field=student.fields.HashCharField(hasher=student.hasher.AESCipher, max_length=256, null=True),
),
]
5 changes: 4 additions & 1 deletion common/djangoapps/student/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,8 @@

from edx_django_utils.cache import RequestCache
import lms.lib.comment_client as cc
from student.hasher import AESCipher
from student.fields import HashCharField
from student.signals import UNENROLL_DONE, ENROLL_STATUS_CHANGE, ENROLLMENT_TRACK_UPDATED
from lms.djangoapps.certificates.models import GeneratedCertificate
from course_modes.models import CourseMode
Expand Down Expand Up @@ -474,7 +476,8 @@ class Meta(object):
bio = models.CharField(blank=True, null=True, max_length=3000, db_index=False)
profile_image_uploaded_at = models.DateTimeField(null=True, blank=True)

phone = models.CharField(_(u"Phone"), max_length=32, null=True)
# phone = models.CharField(_(u"Phone"), max_length=32, null=True)
phone = HashCharField("Phone", max_length=256, null=True, hasher=AESCipher)

@property
def has_profile_image(self):
Expand Down
2 changes: 1 addition & 1 deletion common/djangoapps/util/sms_utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -155,7 +155,7 @@ def send_short_message_by_linkgroup(destnumbers, msg, sendtime='', channel=1):
:param Cell: 扩展号(必须是数字或为空)。
:param channel: 1-签名【E-ducation】。
:return: 实际需返回是否发送成功/失败,以及原因
"""
"""
CorpID = settings.SMS_API_BY_LINKGROUP['normal_auth']['userid'] # 账号
Pwd = settings.SMS_API_BY_LINKGROUP['normal_auth']['password'] # 密码
Mobile = destnumbers
Expand Down
4 changes: 4 additions & 0 deletions lms/envs/common.py
Original file line number Diff line number Diff line change
Expand Up @@ -3470,3 +3470,7 @@ def _make_locale_paths(settings):
from openedx.core.djangoapps.plugins import plugin_apps, plugin_settings, constants as plugin_constants
INSTALLED_APPS.extend(plugin_apps.get_apps(plugin_constants.ProjectType.LMS))
plugin_settings.add_plugins(__name__, plugin_constants.ProjectType.LMS, plugin_constants.SettingsType.COMMON)

############### Settings for AES Encryption/Decryption ##################
AES_KEY = AUTH_TOKENS.get('AES_KEY', '')
AES_IV = AUTH_TOKENS.get('AES_IV', '')

0 comments on commit 0fd0555

Please sign in to comment.